Merge "Address leftover comments"
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index c2586fa..269bbf2 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -15,7 +15,6 @@
*/
package android.net;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -24,8 +23,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-
/**
* A class allowing apps handling the {@link ConnectivityManager#ACTION_CAPTIVE_PORTAL_SIGN_IN}
* activity to indicate to the system different outcomes of captive portal sign in. This class is
@@ -75,17 +72,6 @@
private final IBinder mBinder;
/** @hide */
- @IntDef(value = {
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_ACTIVITY,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_DISMISSED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_UNWANTED,
- MetricsEvent.ACTION_CAPTIVE_PORTAL_LOGIN_RESULT_WANTED_AS_IS,
- MetricsEvent.CAPTIVE_PORTAL_LOGIN_ACTIVITY_SSL_ERROR,
- })
- public @interface EventId {
- }
-
- /** @hide */
public CaptivePortal(@NonNull IBinder binder) {
mBinder = binder;
}
@@ -176,7 +162,7 @@
* @hide
*/
@SystemApi
- public void logEvent(@EventId int eventId, @NonNull String packageName) {
+ public void logEvent(int eventId, @NonNull String packageName) {
try {
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
} catch (RemoteException e) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c28a901..cf5d4e5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -684,7 +684,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @SystemApi
public static final int TYPE_PROXY = 16;
/**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 06046f7..0941e7d 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -81,8 +81,7 @@
private static final int MIN_MTU = 68;
- /** @hide */
- public static final int MIN_MTU_V6 = 1280;
+ private static final int MIN_MTU_V6 = 1280;
private static final int MAX_MTU = 10000;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 44ebff9..0676ad4 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -40,6 +40,7 @@
import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -174,6 +175,14 @@
public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
/**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * list of underlying networks.
+ * obj = array of Network objects
+ * @hide
+ */
+ public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
+
+ /**
* 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.
@@ -217,7 +226,13 @@
* The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
* @hide
*/
- public static String REDIRECT_URL_KEY = "redirect URL";
+ public static final String REDIRECT_URL_KEY = "redirect URL";
+
+ /**
+ * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
+ * @hide
+ */
+ public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
/**
* Sent by the NetworkAgent to ConnectivityService to indicate this network was
@@ -650,6 +665,33 @@
}
/**
+ * Must be called by the agent when the network's underlying networks change.
+ *
+ * <p>{@code networks} is one of the following:
+ * <ul>
+ * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
+ * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
+ * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
+ * first in the array.</li>
+ * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
+ * underlying network connection, and thus, app traffic will not be sent or received.</li>
+ * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
+ * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
+ * APIs mentioned above to send traffic over specific channels.</li>
+ * </ul>
+ *
+ * @param underlyingNetworks the new list of underlying networks.
+ * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
+ */
+ public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
+ final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
+ ? new ArrayList<>(underlyingNetworks) : null;
+ final Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray);
+ queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle);
+ }
+
+ /**
* Inform ConnectivityService that this agent has now connected.
* Call {@link #unregister} to disconnect.
*/
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 40bb8bf..1a37fb9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -712,6 +712,7 @@
if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
setAdministratorUids(new int[] {creatorUid});
}
+ // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
}
/**
@@ -805,7 +806,9 @@
*/
private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
// Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
- | 1 << TRANSPORT_ETHERNET;
+ | 1 << TRANSPORT_ETHERNET
+ // Test VPN networks can be created but their UID ranges must be empty.
+ | 1 << TRANSPORT_VPN;
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
@@ -972,6 +975,10 @@
return mOwnerUid;
}
+ private boolean equalsOwnerUid(@NonNull final NetworkCapabilities nc) {
+ return mOwnerUid == nc.mOwnerUid;
+ }
+
/**
* UIDs of packages that are administrators of this network, or empty if none.
*
@@ -1681,6 +1688,7 @@
&& equalsTransportInfo(that)
&& equalsUids(that)
&& equalsSSID(that)
+ && equalsOwnerUid(that)
&& equalsPrivateDnsBroken(that)
&& equalsRequestor(that)
&& equalsAdministratorUids(that);
@@ -1694,17 +1702,18 @@
+ ((int) (mUnwantedNetworkCapabilities >> 32) * 7)
+ ((int) (mTransportTypes & 0xFFFFFFFF) * 11)
+ ((int) (mTransportTypes >> 32) * 13)
- + (mLinkUpBandwidthKbps * 17)
- + (mLinkDownBandwidthKbps * 19)
+ + mLinkUpBandwidthKbps * 17
+ + mLinkDownBandwidthKbps * 19
+ Objects.hashCode(mNetworkSpecifier) * 23
- + (mSignalStrength * 29)
- + Objects.hashCode(mUids) * 31
- + Objects.hashCode(mSSID) * 37
- + Objects.hashCode(mTransportInfo) * 41
- + Objects.hashCode(mPrivateDnsBroken) * 43
- + Objects.hashCode(mRequestorUid) * 47
- + Objects.hashCode(mRequestorPackageName) * 53
- + Arrays.hashCode(mAdministratorUids) * 59;
+ + mSignalStrength * 29
+ + mOwnerUid * 31
+ + Objects.hashCode(mUids) * 37
+ + Objects.hashCode(mSSID) * 41
+ + Objects.hashCode(mTransportInfo) * 43
+ + Objects.hashCode(mPrivateDnsBroken) * 47
+ + Objects.hashCode(mRequestorUid) * 53
+ + Objects.hashCode(mRequestorPackageName) * 59
+ + Arrays.hashCode(mAdministratorUids) * 61;
}
@Override
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index d31218d..14cb51c 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -51,13 +51,6 @@
public static final int ID_NONE = -1;
/**
- * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
- * provider, so they use this constant for clarity instead of NONE.
- * @hide only used by ConnectivityService.
- */
- public static final int ID_VPN = -2;
-
- /**
* The first providerId value that will be allocated.
* @hide only used by ConnectivityService.
*/
@@ -70,7 +63,7 @@
private final Messenger mMessenger;
private final String mName;
- private final ConnectivityManager mCm;
+ private final Context mContext;
private int mProviderId = ID_NONE;
@@ -85,8 +78,6 @@
*/
@SystemApi
public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) {
- mCm = ConnectivityManager.from(context);
-
Handler handler = new Handler(looper) {
@Override
public void handleMessage(Message m) {
@@ -102,6 +93,7 @@
}
}
};
+ mContext = context;
mMessenger = new Messenger(handler);
mName = name;
}
@@ -165,6 +157,6 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) {
- mCm.declareNetworkRequestUnfulfillable(request);
+ ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request);
}
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index a0faafa..d84ee2a 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -35,7 +35,6 @@
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
-import java.util.Collection;
import java.util.Locale;
import java.util.TreeSet;
@@ -342,20 +341,6 @@
}
/**
- * Create a string array of host addresses from a collection of InetAddresses
- * @param addrs a Collection of InetAddresses
- * @return an array of Strings containing their host addresses
- */
- public static String[] makeStrings(Collection<InetAddress> addrs) {
- String[] result = new String[addrs.size()];
- int i = 0;
- for (InetAddress addr : addrs) {
- result[i++] = addr.getHostAddress();
- }
- return result;
- }
-
- /**
* Trim leading zeros from IPv4 address strings
* Our base libraries will interpret that as octel..
* Must leave non v4 addresses and host names alone.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d275d65..a42c864 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -41,6 +41,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -139,7 +140,6 @@
import android.net.util.LinkPropertiesUtils.CompareResult;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
-import android.os.BasicShellCommandHandler;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -171,7 +171,6 @@
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.Xml;
@@ -187,11 +186,11 @@
import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.BasicShellCommandHandler;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
@@ -1287,7 +1286,7 @@
if (network == null) {
return null;
}
- return getNetworkAgentInfoForNetId(network.netId);
+ return getNetworkAgentInfoForNetId(network.getNetId());
}
private NetworkAgentInfo getNetworkAgentInfoForNetId(int netId) {
@@ -1378,7 +1377,7 @@
}
final String action = blocked ? "BLOCKED" : "UNBLOCKED";
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.netId));
+ "%s %d(%d) on netId %d", action, nri.mUid, nri.request.requestId, net.getNetId()));
}
/**
@@ -1890,7 +1889,7 @@
int netId;
synchronized (nai) {
lp = nai.linkProperties;
- netId = nai.network.netId;
+ netId = nai.network.getNetId();
}
boolean ok = addLegacyRouteToHost(lp, addr, netId, uid);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
@@ -1972,7 +1971,7 @@
private void registerNetdEventCallback() {
final IIpConnectivityMetrics ipConnectivityMetrics = mDeps.getIpConnectivityMetrics();
if (ipConnectivityMetrics == null) {
- Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
+ Log.wtf(TAG, "Missing IIpConnectivityMetrics");
return;
}
@@ -2438,7 +2437,7 @@
if (VDBG || DDBG) log("Setting MTU size: " + iface + ", " + mtu);
mNetd.interfaceSetMtu(iface, mtu);
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "exception in interfaceSetMtu()" + e);
+ loge("exception in interfaceSetMtu()" + e);
}
}
@@ -2460,7 +2459,7 @@
if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
try {
- if (VDBG || DDBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
+ if (VDBG || DDBG) log("Setting tx/rx TCP buffers to " + tcpBufferSizes);
String rmemValues = String.join(" ", values[0], values[1], values[2]);
String wmemValues = String.join(" ", values[3], values[4], values[5]);
@@ -2525,9 +2524,21 @@
PriorityDump.dump(mPriorityDumper, fd, writer, args);
}
+ private boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
+ if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump " + tag + " from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " due to missing android.permission.DUMP permission");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
private void doDump(FileDescriptor fd, PrintWriter writer, String[] args, boolean asProto) {
final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ if (!checkDumpPermission(mContext, TAG, pw)) return;
if (asProto) return;
if (ArrayUtils.contains(args, DIAG_ARG)) {
@@ -2553,7 +2564,7 @@
if (defaultNai == null) {
pw.println("none");
} else {
- pw.println(defaultNai.network.netId);
+ pw.println(defaultNai.network.getNetId());
}
pw.println();
@@ -2690,17 +2701,23 @@
private NetworkAgentInfo[] networksSortedById() {
NetworkAgentInfo[] networks = new NetworkAgentInfo[0];
networks = mNetworkAgentInfos.values().toArray(networks);
- Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.netId));
+ Arrays.sort(networks, Comparator.comparingInt(nai -> nai.network.getNetId()));
return networks;
}
/**
* Return an array of all current NetworkRequest sorted by request id.
*/
- private NetworkRequestInfo[] requestsSortedById() {
+ @VisibleForTesting
+ protected NetworkRequestInfo[] requestsSortedById() {
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
requests = mNetworkRequests.values().toArray(requests);
- Arrays.sort(requests, Comparator.comparingInt(nri -> nri.request.requestId));
+ // Sort the array based off the NRI containing the min requestId in its requests.
+ Arrays.sort(requests,
+ Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
+ Comparator.comparingInt(req -> req.requestId)).requestId
+ )
+ );
return requests;
}
@@ -2755,7 +2772,7 @@
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
if (networkCapabilities.hasConnectivityManagedCapability()) {
- Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
+ Log.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
}
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
// Make sure the original object is not mutated. NetworkAgent normally
@@ -2765,6 +2782,7 @@
networkCapabilities = new NetworkCapabilities(networkCapabilities);
networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
}
+ processCapabilitiesFromAgent(nai, networkCapabilities);
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
}
@@ -2803,6 +2821,31 @@
mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
break;
}
+ case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
+ if (!nai.supportsUnderlyingNetworks()) {
+ Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
+ break;
+ }
+ final ArrayList<Network> underlying;
+ try {
+ underlying = ((Bundle) msg.obj).getParcelableArrayList(
+ NetworkAgent.UNDERLYING_NETWORKS_KEY);
+ } catch (NullPointerException | ClassCastException e) {
+ break;
+ }
+ final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
+ nai.declaredUnderlyingNetworks = (underlying != null)
+ ? underlying.toArray(new Network[0]) : null;
+
+ if (!Arrays.equals(oldUnderlying, nai.declaredUnderlyingNetworks)) {
+ if (DBG) {
+ log(nai.toShortString() + " changed underlying networks to "
+ + Arrays.toString(nai.declaredUnderlyingNetworks));
+ }
+ updateCapabilitiesForNetwork(nai);
+ notifyIfacesChangedForNetworkStats();
+ }
+ }
}
}
@@ -2823,8 +2866,7 @@
if (probePrivateDnsCompleted) {
if (nai.networkCapabilities.isPrivateDnsBroken() != privateDnsBroken) {
nai.networkCapabilities.setPrivateDnsBroken(privateDnsBroken);
- final int oldScore = nai.getCurrentScore();
- updateCapabilities(oldScore, nai, nai.networkCapabilities);
+ updateCapabilitiesForNetwork(nai);
}
// Only show the notification when the private DNS is broken and the
// PRIVATE_DNS_BROKEN notification hasn't shown since last valid.
@@ -2839,8 +2881,7 @@
// done yet. In either case, the networkCapabilities should be updated to
// reflect the new status.
nai.networkCapabilities.setPrivateDnsBroken(false);
- final int oldScore = nai.getCurrentScore();
- updateCapabilities(oldScore, nai, nai.networkCapabilities);
+ updateCapabilitiesForNetwork(nai);
nai.networkAgentConfig.hasShownBroken = false;
}
break;
@@ -2861,7 +2902,6 @@
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
// If captive portal status has changed, update capabilities or disconnect.
if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
- final int oldScore = nai.getCurrentScore();
nai.lastCaptivePortalDetected = visible;
nai.everCaptivePortalDetected |= visible;
if (nai.lastCaptivePortalDetected &&
@@ -2872,7 +2912,7 @@
teardownUnneededNetwork(nai);
break;
}
- updateCapabilities(oldScore, nai, nai.networkCapabilities);
+ updateCapabilitiesForNetwork(nai);
}
if (!visible) {
// Only clear SIGN_IN and NETWORK_SWITCH notifications here, or else other
@@ -2942,13 +2982,13 @@
handleFreshlyValidatedNetwork(nai);
// Clear NO_INTERNET, PRIVATE_DNS_BROKEN, PARTIAL_CONNECTIVITY and
// LOST_INTERNET notifications if network becomes valid.
- mNotifier.clearNotification(nai.network.netId,
+ mNotifier.clearNotification(nai.network.getNetId(),
NotificationType.NO_INTERNET);
- mNotifier.clearNotification(nai.network.netId,
+ mNotifier.clearNotification(nai.network.getNetId(),
NotificationType.LOST_INTERNET);
- mNotifier.clearNotification(nai.network.netId,
+ mNotifier.clearNotification(nai.network.getNetId(),
NotificationType.PARTIAL_CONNECTIVITY);
- mNotifier.clearNotification(nai.network.netId,
+ mNotifier.clearNotification(nai.network.getNetId(),
NotificationType.PRIVATE_DNS_BROKEN);
// If network becomes valid, the hasShownBroken should be reset for
// that network so that the notification will be fired when the private
@@ -2956,7 +2996,7 @@
nai.networkAgentConfig.hasShownBroken = false;
}
} else if (partialConnectivityChanged) {
- updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+ updateCapabilitiesForNetwork(nai);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -3019,7 +3059,7 @@
private final AutodestructReference<NetworkAgentInfo> mNai;
private NetworkMonitorCallbacks(NetworkAgentInfo nai) {
- mNetId = nai.network.netId;
+ mNetId = nai.network.getNetId();
mNai = new AutodestructReference<>(nai);
}
@@ -3034,7 +3074,7 @@
// Legacy version of notifyNetworkTestedWithExtras.
// Would only be called if the system has a NetworkStack module older than the
// framework, which does not happen in practice.
- Slog.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
+ Log.wtf(TAG, "Deprecated notifyNetworkTested called: no action taken");
}
@Override
@@ -3169,7 +3209,7 @@
// in order to restart a validation pass from within netd.
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
if (cfg.useTls && TextUtils.isEmpty(cfg.hostname)) {
- updateDnses(nai.linkProperties, null, nai.network.netId);
+ updateDnses(nai.linkProperties, null, nai.network.getNetId());
}
}
@@ -3202,7 +3242,7 @@
private void updatePrivateDns(NetworkAgentInfo nai, PrivateDnsConfig newCfg) {
mDnsManager.updatePrivateDns(nai.network, newCfg);
- updateDnses(nai.linkProperties, null, nai.network.netId);
+ updateDnses(nai.linkProperties, null, nai.network.getNetId());
}
private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) {
@@ -3298,9 +3338,9 @@
if (nai != null) {
final boolean wasDefault = isDefaultNetwork(nai);
synchronized (mNetworkForNetId) {
- mNetworkForNetId.remove(nai.network.netId);
+ mNetworkForNetId.remove(nai.network.getNetId());
}
- mNetIdManager.releaseNetId(nai.network.netId);
+ mNetIdManager.releaseNetId(nai.network.getNetId());
// Just in case.
mLegacyTypeTracker.remove(nai, wasDefault);
}
@@ -3330,7 +3370,7 @@
log(nai.toShortString() + " disconnected, was satisfying " + nai.numNetworkRequests());
}
// Clear all notifications of this network.
- mNotifier.clearNotification(nai.network.netId);
+ mNotifier.clearNotification(nai.network.getNetId());
// A network agent has disconnected.
// TODO - if we move the logic to the network agent (have them disconnect
// because they lost all their requests or because their score isn't good)
@@ -3367,14 +3407,15 @@
synchronized (mNetworkForNetId) {
// Remove the NetworkAgent, but don't mark the netId as
// available until we've told netd to delete it below.
- mNetworkForNetId.remove(nai.network.netId);
+ mNetworkForNetId.remove(nai.network.getNetId());
}
// Remove all previously satisfied requests.
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest request = nai.requestAt(i);
final NetworkRequestInfo nri = mNetworkRequests.get(request);
final NetworkAgentInfo currentNetwork = nri.mSatisfier;
- if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+ if (currentNetwork != null
+ && currentNetwork.network.getNetId() == nai.network.getNetId()) {
nri.mSatisfier = null;
sendUpdatedScoreToFactories(request, null);
}
@@ -3388,7 +3429,7 @@
}
mLegacyTypeTracker.remove(nai, wasDefault);
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
@@ -3404,26 +3445,26 @@
destroyNativeNetwork(nai);
mDnsManager.removeNetwork(nai.network);
}
- mNetIdManager.releaseNetId(nai.network.netId);
+ mNetIdManager.releaseNetId(nai.network.getNetId());
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
try {
// This should never fail. Specifying an already in use NetID will cause failure.
if (networkAgent.isVPN()) {
- mNetd.networkCreateVpn(networkAgent.network.netId,
+ mNetd.networkCreateVpn(networkAgent.network.getNetId(),
(networkAgent.networkAgentConfig == null
|| !networkAgent.networkAgentConfig.allowBypass));
} else {
- mNetd.networkCreatePhysical(networkAgent.network.netId,
+ mNetd.networkCreatePhysical(networkAgent.network.getNetId(),
getNetworkPermission(networkAgent.networkCapabilities));
}
- mDnsResolver.createNetworkCache(networkAgent.network.netId);
- mDnsManager.updateTransportsForNetwork(networkAgent.network.netId,
+ mDnsResolver.createNetworkCache(networkAgent.network.getNetId());
+ mDnsManager.updateTransportsForNetwork(networkAgent.network.getNetId(),
networkAgent.networkCapabilities.getTransportTypes());
return true;
} catch (RemoteException | ServiceSpecificException e) {
- loge("Error creating network " + networkAgent.network.netId + ": "
+ loge("Error creating network " + networkAgent.network.getNetId() + ": "
+ e.getMessage());
return false;
}
@@ -3431,8 +3472,8 @@
private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
try {
- mNetd.networkDestroy(networkAgent.network.netId);
- mDnsResolver.destroyNetworkCache(networkAgent.network.netId);
+ mNetd.networkDestroy(networkAgent.network.getNetId());
+ mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception destroying network: " + e);
}
@@ -3511,7 +3552,7 @@
numRequests = nai.numForegroundNetworkRequests();
break;
default:
- Slog.wtf(TAG, "Invalid reason. Cannot happen.");
+ Log.wtf(TAG, "Invalid reason. Cannot happen.");
return true;
}
@@ -3624,7 +3665,7 @@
nri.mSatisfier = null;
if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
// Went from foreground to background.
- updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+ updateCapabilitiesForNetwork(nai);
}
}
@@ -3673,7 +3714,7 @@
synchronized (mUidToNetworkRequestCount) {
final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
if (requests < 1) {
- Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
+ Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
} else if (requests == 1) {
mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
} else {
@@ -3718,7 +3759,7 @@
}
if (!nai.networkAgentConfig.explicitlySelected) {
- Slog.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
+ Log.wtf(TAG, "BUG: setAcceptUnvalidated non non-explicitly selected network");
}
if (accept != nai.networkAgentConfig.acceptUnvalidated) {
@@ -3988,13 +4029,13 @@
highPriority = nai.networkAgentConfig.explicitlySelected;
break;
default:
- Slog.wtf(TAG, "Unknown notification type " + type);
+ Log.wtf(TAG, "Unknown notification type " + type);
return;
}
Intent intent = new Intent(action);
if (type != NotificationType.PRIVATE_DNS_BROKEN) {
- intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
+ intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.getNetId()), null));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Some OEMs have their own Settings package. Thus, need to get the current using
// Settings package name instead of just use default name "com.android.settings".
@@ -4009,7 +4050,8 @@
intent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, highPriority);
+ mNotifier.showNotification(
+ nai.network.getNetId(), type, nai, null, pendingIntent, highPriority);
}
private boolean shouldPromptUnvalidated(NetworkAgentInfo nai) {
@@ -4310,7 +4352,7 @@
synchronized (this) {
if (!mNetTransitionWakeLock.isHeld()) {
mWakelockLogs.log(String.format("RELEASE: already released (%s)", event));
- Slog.w(TAG, "expected Net Transition WakeLock to be held");
+ Log.w(TAG, "expected Net Transition WakeLock to be held");
return;
}
mNetTransitionWakeLock.release();
@@ -4375,7 +4417,7 @@
return;
}
if (DBG) {
- int netid = nai.network.netId;
+ int netid = nai.network.getNetId();
log("reportNetworkConnectivity(" + netid + ", " + hasConnectivity + ") by " + uid);
}
// Validating a network that has not yet connected could result in a call to
@@ -4410,7 +4452,7 @@
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.netId)) {
+ } else if (mDeps.queryUserAccess(Binder.getCallingUid(), network.getNetId())) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -4482,7 +4524,7 @@
@Override
public void onChange(boolean selfChange) {
- Slog.wtf(TAG, "Should never be reached.");
+ Log.wtf(TAG, "Should never be reached.");
}
@Override
@@ -4497,15 +4539,19 @@
}
private static void log(String s) {
- Slog.d(TAG, s);
+ Log.d(TAG, s);
+ }
+
+ private static void logw(String s) {
+ Log.w(TAG, s);
}
private static void loge(String s) {
- Slog.e(TAG, s);
+ Log.e(TAG, s);
}
private static void loge(String s, Throwable t) {
- Slog.e(TAG, s, t);
+ Log.e(TAG, s, t);
}
/**
@@ -4698,10 +4744,9 @@
if (mLockdownEnabled) {
return new VpnInfo[0];
}
-
List<VpnInfo> infoList = new ArrayList<>();
- for (int i = 0; i < mVpns.size(); i++) {
- VpnInfo info = createVpnInfo(mVpns.valueAt(i));
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ VpnInfo info = createVpnInfo(nai);
if (info != null) {
infoList.add(info);
}
@@ -4714,13 +4759,10 @@
* @return VPN information for accounting, or null if we can't retrieve all required
* information, e.g underlying ifaces.
*/
- @Nullable
- private VpnInfo createVpnInfo(Vpn vpn) {
- VpnInfo info = vpn.getVpnInfo();
- if (info == null) {
- return null;
- }
- Network[] underlyingNetworks = vpn.getUnderlyingNetworks();
+ private VpnInfo 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) {
@@ -4729,23 +4771,33 @@
underlyingNetworks = new Network[] { defaultNai.network };
}
}
- if (underlyingNetworks != null && underlyingNetworks.length > 0) {
- List<String> interfaces = new ArrayList<>();
- for (Network network : underlyingNetworks) {
- LinkProperties lp = getLinkProperties(network);
- if (lp != null) {
- for (String iface : lp.getAllInterfaceNames()) {
- if (!TextUtils.isEmpty(iface)) {
- interfaces.add(iface);
- }
- }
+
+ if (ArrayUtils.isEmpty(underlyingNetworks)) return null;
+
+ List<String> interfaces = new ArrayList<>();
+ for (Network network : underlyingNetworks) {
+ NetworkAgentInfo underlyingNai = getNetworkAgentInfoForNetwork(network);
+ if (underlyingNai == null) continue;
+ LinkProperties lp = underlyingNai.linkProperties;
+ for (String iface : lp.getAllInterfaceNames()) {
+ if (!TextUtils.isEmpty(iface)) {
+ interfaces.add(iface);
}
}
- if (!interfaces.isEmpty()) {
- info.underlyingIfaces = interfaces.toArray(new String[interfaces.size()]);
- }
}
- return info.underlyingIfaces == null ? null : info;
+
+ if (interfaces.isEmpty()) return null;
+
+ VpnInfo info = new VpnInfo();
+ info.ownerUid = nai.networkCapabilities.getOwnerUid();
+ info.vpnIface = nai.linkProperties.getInterfaceName();
+ // Must be non-null or NetworkStatsService will crash.
+ // Cannot happen in production code because Vpn only registers the NetworkAgent after the
+ // tun or ipsec interface is created.
+ if (info.vpnIface == null) return null;
+ info.underlyingIfaces = interfaces.toArray(new String[0]);
+
+ return info;
}
/**
@@ -4768,39 +4820,25 @@
}
/**
- * Ask all VPN objects to recompute and update their capabilities.
+ * Ask all networks with underlying networks to recompute and update their capabilities.
*
- * When underlying networks change, VPNs may have to update capabilities to reflect things
- * like the metered bit, their transports, and so on. This asks the VPN objects to update
- * their capabilities, and as this will cause them to send messages to the ConnectivityService
- * handler thread through their agent, this is asynchronous. When the capabilities objects
- * are computed they will be up-to-date as they are computed synchronously from here and
- * this is running on the ConnectivityService thread.
+ * When underlying networks change, such networks may have to update capabilities to reflect
+ * things like the metered bit, their transports, and so on. The capabilities are calculated
+ * immediately. This method runs on the ConnectivityService thread.
*/
- private void updateAllVpnsCapabilities() {
- Network defaultNetwork = getNetwork(getDefaultNetwork());
- synchronized (mVpns) {
- for (int i = 0; i < mVpns.size(); i++) {
- final Vpn vpn = mVpns.valueAt(i);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
+ private void propagateUnderlyingNetworkCapabilities() {
+ ensureRunningOnConnectivityServiceThread();
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.supportsUnderlyingNetworks()) {
+ updateCapabilitiesForNetwork(nai);
}
}
}
- private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
- if (vpnNai == null || nc == null) {
- return;
- }
- updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
- }
-
@Override
public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM");
+ logw("Lockdown VPN only available to AID_SYSTEM");
return false;
}
@@ -4810,21 +4848,21 @@
if (mLockdownEnabled) {
byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
if (profileTag == null) {
- Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+ loge("Lockdown VPN configured but cannot be read from keystore");
return false;
}
String profileName = new String(profileTag);
final VpnProfile profile = VpnProfile.decode(
profileName, mKeyStore.get(Credentials.VPN + profileName));
if (profile == null) {
- Slog.e(TAG, "Lockdown VPN configured invalid profile " + profileName);
+ loge("Lockdown VPN configured invalid profile " + profileName);
setLockdownTracker(null);
return true;
}
int user = UserHandle.getUserId(Binder.getCallingUid());
Vpn vpn = mVpns.get(user);
if (vpn == null) {
- Slog.w(TAG, "VPN for user " + user + " not ready yet. Skipping lockdown");
+ logw("VPN for user " + user + " not ready yet. Skipping lockdown");
return false;
}
setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile));
@@ -4884,7 +4922,7 @@
if (vpn == null) {
// Shouldn't happen as all code paths that point here should have checked the Vpn
// exists already.
- Slog.wtf(TAG, "User " + userId + " has no Vpn configuration");
+ Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
return false;
}
@@ -4900,7 +4938,7 @@
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ logw("User " + userId + " has no Vpn configuration");
return false;
}
return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
@@ -4921,7 +4959,7 @@
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ logw("User " + userId + " has no Vpn configuration");
return false;
}
if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
@@ -4943,7 +4981,7 @@
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ logw("User " + userId + " has no Vpn configuration");
return null;
}
return vpn.getAlwaysOnPackage();
@@ -4958,7 +4996,7 @@
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ logw("User " + userId + " has no Vpn configuration");
return false;
}
return vpn.getLockdown();
@@ -4973,7 +5011,7 @@
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- Slog.w(TAG, "User " + userId + " has no Vpn configuration");
+ logw("User " + userId + " has no Vpn configuration");
return null;
}
return vpn.getLockdownAllowlist();
@@ -5107,7 +5145,7 @@
}
}
- private void onUserStart(int userId) {
+ private void onUserStarted(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
@@ -5122,7 +5160,7 @@
}
}
- private void onUserStop(int userId) {
+ private void onUserStopped(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn == null) {
@@ -5136,35 +5174,29 @@
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserAdded(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserRemoved(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
private void onPackageReplaced(String packageName, int uid) {
if (TextUtils.isEmpty(packageName) || uid < 0) {
- Slog.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
+ Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
return;
}
final int userId = UserHandle.getUserId(uid);
@@ -5175,7 +5207,7 @@
}
// Legacy always-on VPN won't be affected since the package name is not set.
if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
- Slog.d(TAG, "Restarting always-on VPN package " + packageName + " for user "
+ log("Restarting always-on VPN package " + packageName + " for user "
+ userId);
vpn.startAlwaysOnVpn(mKeyStore);
}
@@ -5184,7 +5216,7 @@
private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
if (TextUtils.isEmpty(packageName) || uid < 0) {
- Slog.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+ Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
return;
}
@@ -5196,7 +5228,7 @@
}
// Legacy always-on VPN won't be affected since the package name is not set.
if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
- Slog.d(TAG, "Removing always-on VPN package " + packageName + " for user "
+ log("Removing always-on VPN package " + packageName + " for user "
+ userId);
vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
}
@@ -5239,9 +5271,9 @@
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStart(userId);
+ onUserStarted(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStop(userId);
+ onUserStopped(userId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
@@ -5350,6 +5382,12 @@
}
}
+ private void ensureAllNetworkRequestsHaveType(List<NetworkRequest> requests) {
+ for (int i = 0; i < requests.size(); i++) {
+ ensureNetworkRequestHasType(requests.get(i));
+ }
+ }
+
private void ensureNetworkRequestHasType(NetworkRequest request) {
if (request.type == NetworkRequest.Type.NONE) {
throw new IllegalArgumentException(
@@ -5361,7 +5399,8 @@
* Tracks info about the requester.
* Also used to notice when the calling process dies so we can self-expire
*/
- private class NetworkRequestInfo implements IBinder.DeathRecipient {
+ @VisibleForTesting
+ protected class NetworkRequestInfo implements IBinder.DeathRecipient {
final List<NetworkRequest> mRequests;
final NetworkRequest request;
@@ -5380,7 +5419,7 @@
NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
request = r;
mRequests = initializeRequests(r);
- ensureNetworkRequestHasType(request);
+ ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
messenger = null;
mBinder = null;
@@ -5394,7 +5433,7 @@
messenger = m;
request = r;
mRequests = initializeRequests(r);
- ensureNetworkRequestHasType(request);
+ ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
mUid = getCallingUid();
@@ -5418,6 +5457,19 @@
return Collections.unmodifiableList(tempRequests);
}
+ private NetworkRequest getSatisfiedRequest() {
+ if (mSatisfier == null) {
+ return null;
+ }
+
+ for (NetworkRequest req : mRequests) {
+ if (mSatisfier.isSatisfyingRequest(req.requestId)) {
+ return req;
+ }
+ }
+
+ return null;
+ }
private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) {
@@ -5436,14 +5488,16 @@
}
}
+ @Override
public void binderDied() {
log("ConnectivityService NetworkRequestInfo binderDied(" +
- request + ", " + mBinder + ")");
- releaseNetworkRequest(request);
+ mRequests + ", " + mBinder + ")");
+ releaseNetworkRequest(mRequests);
}
+ @Override
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " " + request
+ return "uid/pid:" + mUid + "/" + mPid + " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
}
@@ -5609,7 +5663,7 @@
return false;
}
synchronized (mNetworkForNetId) {
- nai = mNetworkForNetId.get(network.netId);
+ nai = mNetworkForNetId.get(network.getNetId());
}
if (nai != null) {
nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
@@ -5763,6 +5817,12 @@
return mNextNetworkProviderId.getAndIncrement();
}
+ private void releaseNetworkRequest(List<NetworkRequest> networkRequests) {
+ for (int i = 0; i < networkRequests.size(); i++) {
+ releaseNetworkRequest(networkRequests.get(i));
+ }
+ }
+
@Override
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
@@ -5784,7 +5844,7 @@
// Avoid creating duplicates. even if an app makes a direct AIDL call.
// This will never happen if an app calls ConnectivityManager#registerNetworkProvider,
// as that will throw if a duplicate provider is registered.
- Slog.e(TAG, "Attempt to register existing NetworkProviderInfo "
+ loge("Attempt to register existing NetworkProviderInfo "
+ mNetworkProviderInfos.get(npi.messenger).name);
return;
}
@@ -5925,13 +5985,29 @@
int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
+ } else {
+ enforceNetworkFactoryPermission();
+ }
+
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return registerNetworkAgentInternal(messenger, networkInfo, linkProperties,
+ networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
+ if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
// Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
// sees capabilities that may be malicious, which might prevent mistakes in the future.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
- } else {
- enforceNetworkFactoryPermission();
+ networkCapabilities.restrictCapabilitesForTestNetwork(uid);
}
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5942,9 +6018,10 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
+ this, mNetd, mDnsResolver, mNMS, providerId, uid);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
+ processCapabilitiesFromAgent(nai, nc);
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
processLinkPropertiesFromAgent(nai, nai.linkProperties);
@@ -5952,13 +6029,8 @@
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSsid() : extraInfo;
if (DBG) log("registerNetworkAgent " + nai);
- final long token = Binder.clearCallingIdentity();
- try {
- mDeps.getNetworkStack().makeNetworkMonitor(
- nai.network, name, new NetworkMonitorCallbacks(nai));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mDeps.getNetworkStack().makeNetworkMonitor(
+ nai.network, name, new NetworkMonitorCallbacks(nai));
// NetworkAgentInfo registration will finish when the NetworkMonitor is created.
// If the network disconnects or sends any other event before that, messages are deferred by
// NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
@@ -5971,7 +6043,7 @@
if (VDBG) log("Got NetworkAgent Messenger");
mNetworkAgentInfos.put(nai.messenger, nai);
synchronized (mNetworkForNetId) {
- mNetworkForNetId.put(nai.network.netId, nai);
+ mNetworkForNetId.put(nai.network.getNetId(), nai);
}
try {
@@ -5985,6 +6057,13 @@
updateUids(nai, null, nai.networkCapabilities);
}
+ /**
+ * Called when receiving LinkProperties directly from a NetworkAgent.
+ * Stores into |nai| any data coming from the agent that might also be written to the network's
+ * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
+ * agent is not lost when updateLinkProperties is called.
+ * This method should never alter the agent's LinkProperties, only store data in |nai|.
+ */
private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
lp.ensureDirectlyConnectedRoutes();
nai.clatd.setNat64PrefixFromRa(lp.getNat64Prefix());
@@ -5992,7 +6071,7 @@
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties newLp,
@NonNull LinkProperties oldLp) {
- int netId = networkAgent.network.netId;
+ int netId = networkAgent.network.getNetId();
// The NetworkAgent does not know whether clatd is running on its network or not, or whether
// a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
@@ -6273,7 +6352,7 @@
final int newPermission = getNetworkPermission(newNc);
if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
try {
- mNetd.networkSetPermissionForNetwork(nai.network.netId, newPermission);
+ mNetd.networkSetPermissionForNetwork(nai.network.getNetId(), newPermission);
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception in networkSetPermissionForNetwork: " + e);
}
@@ -6281,6 +6360,89 @@
}
/**
+ * Called when receiving NetworkCapabilities directly from a NetworkAgent.
+ * Stores into |nai| any data coming from the agent that might also be written to the network's
+ * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
+ * agent is not lost when updateCapabilities is called.
+ * This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
+ */
+ private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
+ nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
+ if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
+ Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
+ + nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
+ nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
+ }
+ }
+
+ /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+ @VisibleForTesting
+ void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
+ @NonNull NetworkCapabilities caps, boolean declaredMetered) {
+ final Network defaultNetwork = getNetwork(getDefaultNetwork());
+ if (underlyingNetworks == null && defaultNetwork != null) {
+ // null underlying networks means to track the default.
+ underlyingNetworks = new Network[] { defaultNetwork };
+ }
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+ boolean roaming = false; // roaming if any underlying is roaming
+ boolean congested = false; // congested if any underlying is congested
+ boolean suspended = true; // suspended if all underlying are suspended
+
+ boolean hadUnderlyingNetworks = false;
+ if (null != underlyingNetworks) {
+ for (Network underlyingNetwork : underlyingNetworks) {
+ final NetworkAgentInfo underlying =
+ getNetworkAgentInfoForNetwork(underlyingNetwork);
+ if (underlying == null) continue;
+
+ final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
+ hadUnderlyingNetworks = true;
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
+
+ // Merge capabilities of this underlying network. For bandwidth, assume the
+ // worst case.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ // If this underlying network is metered, the VPN is metered (it may cost money
+ // to send packets on this network).
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ // If this underlying network is roaming, the VPN is roaming (the billing structure
+ // is different than the usual, local one).
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ // If this underlying network is congested, the VPN is congested (the current
+ // condition of the network affects the performance of this network).
+ congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
+ // If this network is not suspended, the VPN is not suspended (the VPN
+ // is able to transfer some data).
+ suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
+ }
+ if (!hadUnderlyingNetworks) {
+ // No idea what the underlying networks are; assume reasonable defaults
+ metered = true;
+ roaming = false;
+ congested = false;
+ suspended = false;
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+ caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+ caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+ caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
+ }
+
+ /**
* Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
* and foreground status).
@@ -6299,7 +6461,7 @@
// stop being matched by the updated agent.
String diff = nai.networkCapabilities.describeImmutableDifferences(nc);
if (!TextUtils.isEmpty(diff)) {
- Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
+ Log.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
}
}
@@ -6333,6 +6495,10 @@
newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
+ if (nai.supportsUnderlyingNetworks()) {
+ applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
+ }
+
return newNc;
}
@@ -6412,14 +6578,20 @@
if (!newNc.hasTransport(TRANSPORT_VPN)) {
// Tell VPNs about updated capabilities, since they may need to
// bubble those changes through.
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
if (!newNc.equalsTransportTypes(prevNc)) {
- mDnsManager.updateTransportsForNetwork(nai.network.netId, newNc.getTransportTypes());
+ mDnsManager.updateTransportsForNetwork(
+ nai.network.getNetId(), newNc.getTransportTypes());
}
}
+ /** Convenience method to update the capabilities for a given network. */
+ private void updateCapabilitiesForNetwork(NetworkAgentInfo nai) {
+ updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+ }
+
/**
* Returns whether VPN isolation (ingress interface filtering) should be applied on the given
* network.
@@ -6470,12 +6642,12 @@
if (!newRanges.isEmpty()) {
final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
newRanges.toArray(addedRangesArray);
- mNMS.addVpnUidRanges(nai.network.netId, addedRangesArray);
+ mNMS.addVpnUidRanges(nai.network.getNetId(), addedRangesArray);
}
if (!prevRanges.isEmpty()) {
final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
prevRanges.toArray(removedRangesArray);
- mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+ mNMS.removeVpnUidRanges(nai.network.getNetId(), removedRangesArray);
}
final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
@@ -6506,7 +6678,7 @@
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
ensureRunningOnConnectivityServiceThread();
- if (getNetworkAgentInfoForNetId(nai.network.netId) != nai) {
+ if (getNetworkAgentInfoForNetId(nai.network.getNetId()) != nai) {
// Ignore updates for disconnected networks
return;
}
@@ -6705,8 +6877,7 @@
teardownUnneededNetwork(oldNetwork);
} else {
// Put the network in the background.
- updateCapabilities(oldNetwork.getCurrentScore(), oldNetwork,
- oldNetwork.networkCapabilities);
+ updateCapabilitiesForNetwork(oldNetwork);
}
}
@@ -6717,7 +6888,7 @@
try {
if (null != newNetwork) {
- mNetd.networkSetDefault(newNetwork.network.netId);
+ mNetd.networkSetDefault(newNetwork.network.getNetId());
} else {
mNetd.networkClearDefault();
}
@@ -6732,7 +6903,7 @@
? newNetwork.linkProperties.getTcpBufferSizes() : null);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -6779,9 +6950,9 @@
}
public String toString() {
- return mRequest.request.requestId + " : "
- + (null != mOldNetwork ? mOldNetwork.network.netId : "null")
- + " → " + (null != mNewNetwork ? mNewNetwork.network.netId : "null");
+ return mRequest.mRequests.get(0).requestId + " : "
+ + (null != mOldNetwork ? mOldNetwork.network.getNetId() : "null")
+ + " → " + (null != mNewNetwork ? mNewNetwork.network.getNetId() : "null");
}
}
@@ -6855,7 +7026,7 @@
}
newSatisfier.unlingerRequest(nri.request);
if (!newSatisfier.addRequest(nri.request)) {
- Slog.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
+ Log.wtf(TAG, "BUG: " + newSatisfier.toShortString() + " already has "
+ nri.request);
}
} else {
@@ -7194,7 +7365,7 @@
// onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
// the VPN would switch from its default, blank capabilities to those
// that reflect the capabilities of its underlying networks.
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
networkAgent.created = true;
}
@@ -7203,7 +7374,7 @@
networkAgent.everConnected = true;
if (networkAgent.linkProperties == null) {
- Slog.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
+ Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties");
}
// NetworkCapabilities need to be set before sending the private DNS config to
@@ -7236,8 +7407,8 @@
// doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
- if (networkAgent.isVPN()) {
- updateAllVpnsCapabilities();
+ if (networkAgent.supportsUnderlyingNetworks()) {
+ propagateUnderlyingNetworkCapabilities();
}
// Consider network even though it is not yet validated.
@@ -7494,13 +7665,6 @@
throwIfLockdownEnabled();
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
- if (success) {
- mHandler.post(() -> {
- // Update VPN's capabilities based on updated underlying network set.
- updateAllVpnsCapabilities();
- notifyIfacesChangedForNetworkStats();
- });
- }
return success;
}
@@ -7652,7 +7816,7 @@
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
int[] transports = nai.networkCapabilities.getTransportTypes();
- mMetricsLog.log(nai.network.netId, transports, new NetworkEvent(evtype));
+ mMetricsLog.log(nai.network.getNetId(), transports, new NetworkEvent(evtype));
}
private static boolean toBool(int encodedBoolean) {
@@ -8058,8 +8222,10 @@
final NetworkRequestInfo nri = cbInfo.mRequestInfo;
- if (uid != nri.mUid) {
- if (VDBG) loge("Different uid than registrant attempting to unregister cb");
+ // Caller's UID must either be the registrants (if they are unregistering) or the System's
+ // (if the Binder died)
+ if (uid != nri.mUid && uid != Process.SYSTEM_UID) {
+ if (DBG) loge("Uid(" + uid + ") not registrant's (" + nri.mUid + ") or System's");
return;
}
@@ -8176,13 +8342,12 @@
return false;
}
- final Network[] underlyingNetworks;
- synchronized (mVpns) {
- final Vpn vpn = getVpnIfOwner(callbackUid);
- underlyingNetworks = (vpn == null) ? null : vpn.getUnderlyingNetworks();
- }
- if (underlyingNetworks != null) {
- if (Arrays.asList(underlyingNetworks).contains(nai.network)) return true;
+ for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) {
+ if (virtual.supportsUnderlyingNetworks()
+ && virtual.networkCapabilities.getOwnerUid() == callbackUid
+ && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+ return true;
+ }
}
// Administrator UIDs also contains the Owner UID
@@ -8273,6 +8438,6 @@
KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS);
}
- notifyDataStallSuspected(p, network.netId);
+ notifyDataStallSuspected(p, network.getNetId());
}
}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d6bd5a1..75ebe70 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -29,9 +29,9 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.StringNetworkSpecifier;
import android.net.TestNetworkInterface;
@@ -62,7 +62,8 @@
/** @hide */
class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
- @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
+ @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent";
+ @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = TAG;
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -72,6 +73,9 @@
@NonNull private final HandlerThread mHandlerThread;
@NonNull private final Handler mHandler;
+ @NonNull private final ConnectivityManager mCm;
+ @NonNull private final NetworkProvider mNetworkProvider;
+
// Native method stubs
private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@@ -85,6 +89,10 @@
mContext = Objects.requireNonNull(context, "missing Context");
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
+ TEST_NETWORK_PROVIDER_NAME);
+ mCm.registerNetworkProvider(mNetworkProvider);
}
/**
@@ -150,9 +158,6 @@
private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
private final int mUid;
- @NonNull private final NetworkInfo mNi;
- @NonNull private final NetworkCapabilities mNc;
- @NonNull private final LinkProperties mLp;
@GuardedBy("mBinderLock")
@NonNull
@@ -161,20 +166,18 @@
@NonNull private final Object mBinderLock = new Object();
private TestNetworkAgent(
- @NonNull Looper looper,
@NonNull Context context,
- @NonNull NetworkInfo ni,
+ @NonNull Looper looper,
+ @NonNull NetworkAgentConfig config,
@NonNull NetworkCapabilities nc,
@NonNull LinkProperties lp,
int uid,
- @NonNull IBinder binder)
+ @NonNull IBinder binder,
+ @NonNull NetworkProvider np)
throws RemoteException {
- super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE);
+ super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np);
mUid = uid;
- mNi = ni;
- mNc = nc;
- mLp = lp;
synchronized (mBinderLock) {
mBinder = binder; // Binder null-checks in create()
@@ -203,9 +206,7 @@
}
private void teardown() {
- mNi.setDetailedState(DetailedState.DISCONNECTED, null, null);
- mNi.setIsAvailable(false);
- sendNetworkInfo(mNi);
+ unregister();
// Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
// once (otherwise it could throw an exception)
@@ -219,7 +220,7 @@
// Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up
// resources, even for binder death or unwanted calls.
synchronized (mTestNetworkTracker) {
- mTestNetworkTracker.remove(getNetwork().netId);
+ mTestNetworkTracker.remove(getNetwork().getNetId());
}
}
}
@@ -238,11 +239,6 @@
Objects.requireNonNull(context, "missing Context");
// iface and binder validity checked by caller
- // Build network info with special testing type
- NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
- ni.setDetailedState(DetailedState.CONNECTED, null, null);
- ni.setIsAvailable(true);
-
// Build narrow set of NetworkCapabilities, useful only for testing
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll(); // Remove default capabilities.
@@ -290,7 +286,12 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
}
- return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
+ final TestNetworkAgent agent = new TestNetworkAgent(context, looper,
+ new NetworkAgentConfig.Builder().build(), nc, lp, callingUid, binder,
+ mNetworkProvider);
+ agent.register();
+ agent.markConnected();
+ return agent;
}
/**
@@ -338,7 +339,7 @@
administratorUids,
binder);
- mTestNetworkTracker.put(agent.getNetwork().netId, agent);
+ mTestNetworkTracker.put(agent.getNetwork().getNetId(), agent);
}
} catch (SocketException e) {
throw new UncheckedIOException(e);
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index c789186..c70bb08 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -34,7 +34,6 @@
import android.net.IDnsResolver;
import android.net.LinkProperties;
import android.net.Network;
-import android.net.NetworkUtils;
import android.net.ResolverOptionsParcel;
import android.net.ResolverParamsParcel;
import android.net.Uri;
@@ -45,11 +44,12 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import java.net.InetAddress;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -59,7 +59,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
-
/**
* Encapsulate the management of DNS settings for networks.
*
@@ -266,23 +265,23 @@
}
public void removeNetwork(Network network) {
- mPrivateDnsMap.remove(network.netId);
- mPrivateDnsValidationMap.remove(network.netId);
- mTransportsMap.remove(network.netId);
- mLinkPropertiesMap.remove(network.netId);
+ mPrivateDnsMap.remove(network.getNetId());
+ mPrivateDnsValidationMap.remove(network.getNetId());
+ mTransportsMap.remove(network.getNetId());
+ mLinkPropertiesMap.remove(network.getNetId());
}
// This is exclusively called by ConnectivityService#dumpNetworkDiagnostics() which
// is not on the ConnectivityService handler thread.
public PrivateDnsConfig getPrivateDnsConfig(@NonNull Network network) {
- return mPrivateDnsMap.getOrDefault(network.netId, PRIVATE_DNS_OFF);
+ return mPrivateDnsMap.getOrDefault(network.getNetId(), PRIVATE_DNS_OFF);
}
public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
- Slog.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
+ Log.w(TAG, "updatePrivateDns(" + network + ", " + cfg + ")");
return (cfg != null)
- ? mPrivateDnsMap.put(network.netId, cfg)
- : mPrivateDnsMap.remove(network.netId);
+ ? mPrivateDnsMap.put(network.getNetId(), cfg)
+ : mPrivateDnsMap.remove(network.getNetId());
}
public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
@@ -309,8 +308,7 @@
}
public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
- final PrivateDnsValidationStatuses statuses =
- mPrivateDnsValidationMap.get(update.netId);
+ final PrivateDnsValidationStatuses statuses = mPrivateDnsValidationMap.get(update.netId);
if (statuses == null) return;
statuses.updateStatus(update);
}
@@ -364,12 +362,11 @@
paramsParcel.successThreshold = mSuccessThreshold;
paramsParcel.minSamples = mMinSamples;
paramsParcel.maxSamples = mMaxSamples;
- paramsParcel.servers =
- NetworkUtils.makeStrings(lp.getDnsServers());
+ paramsParcel.servers = makeStrings(lp.getDnsServers());
paramsParcel.domains = getDomainStrings(lp.getDomains());
paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
paramsParcel.tlsServers =
- strictMode ? NetworkUtils.makeStrings(
+ strictMode ? makeStrings(
Arrays.stream(privateDnsCfg.ips)
.filter((ip) -> lp.isReachable(ip))
.collect(Collectors.toList()))
@@ -389,7 +386,7 @@
mPrivateDnsValidationMap.remove(netId);
}
- Slog.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+ Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
+ "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers),
Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds,
paramsParcel.successThreshold, paramsParcel.minSamples,
@@ -400,7 +397,7 @@
try {
mDnsResolver.setResolverConfiguration(paramsParcel);
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error setting DNS configuration: " + e);
+ Log.e(TAG, "Error setting DNS configuration: " + e);
return;
}
}
@@ -431,8 +428,8 @@
DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
if (mSampleValidity < 0 || mSampleValidity > 65535) {
- Slog.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default=" +
- DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
+ Log.w(TAG, "Invalid sampleValidity=" + mSampleValidity + ", using default="
+ + DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
mSampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
}
@@ -440,17 +437,17 @@
DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
if (mSuccessThreshold < 0 || mSuccessThreshold > 100) {
- Slog.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default=" +
- DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
+ Log.w(TAG, "Invalid successThreshold=" + mSuccessThreshold + ", using default="
+ + DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
mSuccessThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
}
mMinSamples = getIntSetting(DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
mMaxSamples = getIntSetting(DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
if (mMinSamples < 0 || mMinSamples > mMaxSamples || mMaxSamples > 64) {
- Slog.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples +
- "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", " +
- DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
+ Log.w(TAG, "Invalid sample count (min, max)=(" + mMinSamples + ", " + mMaxSamples
+ + "), using default=(" + DNS_RESOLVER_DEFAULT_MIN_SAMPLES + ", "
+ + DNS_RESOLVER_DEFAULT_MAX_SAMPLES + ")");
mMinSamples = DNS_RESOLVER_DEFAULT_MIN_SAMPLES;
mMaxSamples = DNS_RESOLVER_DEFAULT_MAX_SAMPLES;
}
@@ -460,6 +457,21 @@
return Settings.Global.getInt(mContentResolver, which, dflt);
}
+ /**
+ * Create a string array of host addresses from a collection of InetAddresses
+ *
+ * @param addrs a Collection of InetAddresses
+ * @return an array of Strings containing their host addresses
+ */
+ private String[] makeStrings(Collection<InetAddress> addrs) {
+ String[] result = new String[addrs.size()];
+ int i = 0;
+ for (InetAddress addr : addrs) {
+ result[i++] = addr.getHostAddress();
+ }
+ return result;
+ }
+
private static String getPrivateDnsMode(ContentResolver cr) {
String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 8625a6f..96cbfde 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -40,11 +40,11 @@
import android.annotation.Nullable;
import android.content.Context;
import android.net.ISocketKeepaliveCallback;
+import android.net.InetAddresses;
import android.net.InvalidPacketException;
import android.net.KeepalivePacketData;
import android.net.NattKeepalivePacketData;
import android.net.NetworkAgent;
-import android.net.NetworkUtils;
import android.net.SocketKeepalive.InvalidSocketException;
import android.net.TcpKeepalivePacketData;
import android.net.util.KeepaliveUtils;
@@ -625,8 +625,8 @@
InetAddress srcAddress, dstAddress;
try {
- srcAddress = NetworkUtils.numericToInetAddress(srcAddrString);
- dstAddress = NetworkUtils.numericToInetAddress(dstAddrString);
+ srcAddress = InetAddresses.parseNumericAddress(srcAddrString);
+ dstAddress = InetAddresses.parseNumericAddress(dstAddrString);
} catch (IllegalArgumentException e) {
notifyErrorCallback(cb, ERROR_INVALID_IP_ADDRESS);
return;
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index f99f4c6..adec7ad 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -114,7 +114,7 @@
private int getNotificationSource(NetworkAgentInfo toNai) {
for (int i = 0; i < mNotifications.size(); i++) {
- if (mNotifications.valueAt(i) == toNai.network.netId) {
+ if (mNotifications.valueAt(i) == toNai.network.getNetId()) {
return mNotifications.keyAt(i);
}
}
@@ -122,7 +122,7 @@
}
private boolean everNotified(NetworkAgentInfo nai) {
- return mEverNotified.get(nai.network.netId, false);
+ return mEverNotified.get(nai.network.getNetId(), false);
}
@VisibleForTesting
@@ -153,7 +153,7 @@
}
private void showNotification(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
- mNotifier.showNotification(fromNai.network.netId, NotificationType.NETWORK_SWITCH,
+ mNotifier.showNotification(fromNai.network.getNetId(), NotificationType.NETWORK_SWITCH,
fromNai, toNai, createNotificationIntent(), true);
}
@@ -208,8 +208,8 @@
+ " type=" + sNotifyTypeNames.get(notifyType, "unknown(" + notifyType + ")"));
}
- mNotifications.put(fromNai.network.netId, toNai.network.netId);
- mEverNotified.put(fromNai.network.netId, true);
+ mNotifications.put(fromNai.network.getNetId(), toNai.network.getNetId());
+ mEverNotified.put(fromNai.network.getNetId(), true);
}
/**
@@ -295,8 +295,8 @@
}
public void noteDisconnect(NetworkAgentInfo nai) {
- mNotifications.delete(nai.network.netId);
- mEverNotified.delete(nai.network.netId);
+ mNotifications.delete(nai.network.getNetId());
+ mEverNotified.delete(nai.network.getNetId());
maybeStopNotifying(nai);
// No need to cancel notifications on nai: NetworkMonitor does that on disconnect.
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 163788f..c1b1b6a 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -30,7 +30,7 @@
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -176,7 +176,7 @@
try {
mNMService.registerObserver(this);
} catch (RemoteException e) {
- Slog.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
+ Log.e(TAG, "Can't register iface observer for clat on " + mNetwork.toShortString());
return;
}
@@ -185,7 +185,7 @@
try {
addrStr = mNetd.clatdStart(baseIface, mNat64PrefixInUse.toString());
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
+ Log.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
}
mIface = CLAT_PREFIX + baseIface;
mBaseIface = baseIface;
@@ -193,7 +193,7 @@
try {
mIPv6Address = (Inet6Address) InetAddresses.parseNumericAddress(addrStr);
} catch (ClassCastException | IllegalArgumentException | NullPointerException e) {
- Slog.e(TAG, "Invalid IPv6 address " + addrStr);
+ Log.e(TAG, "Invalid IPv6 address " + addrStr);
}
if (mPrefixDiscoveryRunning && !isPrefixDiscoveryNeeded()) {
stopPrefixDiscovery();
@@ -218,7 +218,7 @@
try {
mNMService.unregisterObserver(this);
} catch (RemoteException | IllegalStateException e) {
- Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
+ Log.e(TAG, "Error unregistering clatd observer on " + mBaseIface + ": " + e);
}
mNat64PrefixInUse = null;
mIface = null;
@@ -242,37 +242,37 @@
@VisibleForTesting
protected void start() {
if (isStarted()) {
- Slog.e(TAG, "startClat: already started");
+ Log.e(TAG, "startClat: already started");
return;
}
if (mNetwork.linkProperties == null) {
- Slog.e(TAG, "startClat: Can't start clat with null LinkProperties");
+ Log.e(TAG, "startClat: Can't start clat with null LinkProperties");
return;
}
String baseIface = mNetwork.linkProperties.getInterfaceName();
if (baseIface == null) {
- Slog.e(TAG, "startClat: Can't start clat on null interface");
+ Log.e(TAG, "startClat: Can't start clat on null interface");
return;
}
// TODO: should we only do this if mNetd.clatdStart() succeeds?
- Slog.i(TAG, "Starting clatd on " + baseIface);
+ Log.i(TAG, "Starting clatd on " + baseIface);
enterStartingState(baseIface);
}
@VisibleForTesting
protected void stop() {
if (!isStarted()) {
- Slog.e(TAG, "stopClat: already stopped");
+ Log.e(TAG, "stopClat: already stopped");
return;
}
- Slog.i(TAG, "Stopping clatd on " + mBaseIface);
+ Log.i(TAG, "Stopping clatd on " + mBaseIface);
try {
mNetd.clatdStop(mBaseIface);
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
+ Log.e(TAG, "Error stopping clatd on " + mBaseIface + ": " + e);
}
String iface = mIface;
@@ -294,7 +294,7 @@
try {
mDnsResolver.startPrefix64Discovery(getNetId());
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
+ Log.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
}
mPrefixDiscoveryRunning = true;
}
@@ -303,7 +303,7 @@
try {
mDnsResolver.stopPrefix64Discovery(getNetId());
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
+ Log.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
}
mPrefixDiscoveryRunning = false;
}
@@ -320,7 +320,7 @@
try {
mDnsResolver.setPrefix64(getNetId(), prefixString);
} catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
+ Log.e(TAG, "Error setting NAT64 prefix on netId " + getNetId() + " to "
+ prefix + ": " + e);
}
}
@@ -328,7 +328,7 @@
private void maybeHandleNat64PrefixChange() {
final IpPrefix newPrefix = selectNat64Prefix();
if (!Objects.equals(mNat64PrefixInUse, newPrefix)) {
- Slog.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
+ Log.d(TAG, "NAT64 prefix changed from " + mNat64PrefixInUse + " to "
+ newPrefix);
stop();
// It's safe to call update here, even though this method is called from update, because
@@ -418,7 +418,7 @@
return;
}
- Slog.d(TAG, "clatd running, updating NAI for " + mIface);
+ Log.d(TAG, "clatd running, updating NAI for " + mIface);
for (LinkProperties stacked: oldLp.getStackedLinks()) {
if (Objects.equals(mIface, stacked.getInterfaceName())) {
lp.addStackedLink(stacked);
@@ -451,7 +451,7 @@
return new LinkAddress(
InetAddresses.parseNumericAddress(config.ipv4Addr), config.prefixLength);
} catch (IllegalArgumentException | RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Error getting link properties: " + e);
+ Log.e(TAG, "Error getting link properties: " + e);
return null;
}
}
@@ -480,11 +480,11 @@
LinkAddress clatAddress = getLinkAddress(iface);
if (clatAddress == null) {
- Slog.e(TAG, "clatAddress was null for stacked iface " + iface);
+ Log.e(TAG, "clatAddress was null for stacked iface " + iface);
return;
}
- Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
+ Log.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s",
mIface, mIface, mBaseIface));
enterRunningState();
LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
@@ -503,7 +503,7 @@
return;
}
- Slog.i(TAG, "interface " + iface + " removed");
+ Log.i(TAG, "interface " + iface + " removed");
// If we're running, and the interface was removed, then we didn't call stop(), and it's
// likely that clatd crashed. Ensure we call stop() so we can start clatd again. Calling
// stop() will also update LinkProperties, and if clatd crashed, the LinkProperties update
@@ -528,6 +528,6 @@
@VisibleForTesting
protected int getNetId() {
- return mNetwork.network.netId;
+ return mNetwork.network.getNetId();
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a9f62d9..ccd1f3b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -132,6 +132,16 @@
// TODO: make this private with a getter.
public NetworkCapabilities networkCapabilities;
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
+ // not guaranteed to be current or correct, or even to exist.
+ public @Nullable Network[] declaredUnderlyingNetworks;
+
+ // Whether this network is always metered even if its underlying networks are unmetered.
+ // Only relevant if #supportsUnderlyingNetworks is true.
+ public boolean declaredMetered;
+
// Indicates if netd has been told to create this Network. From this point on the appropriate
// routing rules are setup and routes are added so packets can begin flowing over the Network.
// This is a sticky bit; once set it is never cleared.
@@ -474,10 +484,16 @@
networkCapabilities);
}
+ /** Whether this network is a VPN. */
public boolean isVPN() {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
+ /** Whether this network might have underlying networks. Currently only true for VPNs. */
+ public boolean supportsUnderlyingNetworks() {
+ return isVPN();
+ }
+
private int getCurrentScore(boolean pretendValidated) {
// TODO: We may want to refactor this into a NetworkScore class that takes a base score from
// the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
@@ -594,7 +610,7 @@
if (newExpiry > 0) {
mLingerMessage = new WakeupMessage(
mContext, mHandler,
- "NETWORK_LINGER_COMPLETE." + network.netId /* cmdName */,
+ "NETWORK_LINGER_COMPLETE." + network.getNetId() /* cmdName */,
EVENT_NETWORK_LINGER_COMPLETE /* cmd */,
0 /* arg1 (unused) */, 0 /* arg2 (unused) */,
this /* obj (NetworkAgentInfo) */);
@@ -685,7 +701,7 @@
* This represents the network with something like "[100 WIFI|VPN]" or "[108 MOBILE]".
*/
public String toShortString() {
- return "[" + network.netId + " "
+ return "[" + network.getNetId() + " "
+ transportNamesOf(networkCapabilities.getTransportTypes()) + "]";
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 49c16ad..a7be657 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -20,10 +20,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
-import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.TrafficStats;
import android.net.shared.PrivateDnsConfig;
@@ -97,8 +97,8 @@
public class NetworkDiagnostics {
private static final String TAG = "NetworkDiagnostics";
- private static final InetAddress TEST_DNS4 = NetworkUtils.numericToInetAddress("8.8.8.8");
- private static final InetAddress TEST_DNS6 = NetworkUtils.numericToInetAddress(
+ private static final InetAddress TEST_DNS4 = InetAddresses.parseNumericAddress("8.8.8.8");
+ private static final InetAddress TEST_DNS6 = InetAddresses.parseNumericAddress(
"2001:4860:4860::8888");
// For brevity elsewhere.
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 7f4fb40..7795ed3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -35,7 +35,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.widget.Toast;
@@ -175,7 +175,7 @@
final int previousEventId = mNotificationTypeMap.get(id);
final NotificationType previousNotifyType = NotificationType.getFromId(previousEventId);
if (priority(previousNotifyType) > priority(notifyType)) {
- Slog.d(TAG, String.format(
+ Log.d(TAG, String.format(
"ignoring notification %s for network %s with existing notification %s",
notifyType, id, previousNotifyType));
return;
@@ -183,7 +183,7 @@
clearNotification(id);
if (DBG) {
- Slog.d(TAG, String.format(
+ Log.d(TAG, String.format(
"showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
@@ -253,7 +253,7 @@
// are sent, but they are not implemented yet.
return;
} else {
- Slog.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+ Log.wtf(TAG, "Unknown notification type " + notifyType + " on network transport "
+ getTransportName(transportType));
return;
}
@@ -294,7 +294,7 @@
try {
mNotificationManager.notify(tag, eventId, notification);
} catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
+ Log.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
}
@@ -317,13 +317,13 @@
final String tag = tagFor(id);
final int eventId = mNotificationTypeMap.get(id);
if (DBG) {
- Slog.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
+ Log.d(TAG, String.format("clearing notification tag=%s event=%s", tag,
nameOf(eventId)));
}
try {
mNotificationManager.cancel(tag, eventId);
} catch (NullPointerException npe) {
- Slog.d(TAG, String.format(
+ Log.d(TAG, String.format(
"failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
}
mNotificationTypeMap.delete(id);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a..4c63eb4 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -174,7 +174,7 @@
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
+ List<UserInfo> users = mUserManager.getAliveUsers();
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index 26cc3ee..5cb3d94 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -35,7 +35,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.annotations.GuardedBy;
@@ -168,7 +168,7 @@
proxyProperties = new ProxyInfo(host, port, exclList);
}
if (!proxyProperties.isValid()) {
- if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
+ if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyProperties);
return;
}
@@ -223,7 +223,7 @@
if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
return;
}
- if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
+ if (DBG) Log.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -255,7 +255,7 @@
if (proxyInfo != null && (!TextUtils.isEmpty(proxyInfo.getHost()) ||
!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))) {
if (!proxyInfo.isValid()) {
- if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+ if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
}
mGlobalProxy = new ProxyInfo(proxyInfo);
@@ -296,7 +296,7 @@
synchronized (mProxyLock) {
if (Objects.equals(mDefaultProxy, proxyInfo)) return;
if (proxyInfo != null && !proxyInfo.isValid()) {
- if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+ if (DBG) Log.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
return;
}
diff --git a/tests/net/common/java/android/net/LinkAddressTest.java b/tests/net/common/java/android/net/LinkAddressTest.java
index 60308e3..1eaf30c 100644
--- a/tests/net/common/java/android/net/LinkAddressTest.java
+++ b/tests/net/common/java/android/net/LinkAddressTest.java
@@ -68,8 +68,8 @@
private static final String V4 = "192.0.2.1";
private static final String V6 = "2001:db8::1";
- private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
- private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
+ private static final InetAddress V4_ADDRESS = InetAddresses.parseNumericAddress(V4);
+ private static final InetAddress V6_ADDRESS = InetAddresses.parseNumericAddress(V6);
@Test
public void testConstants() {
@@ -131,10 +131,10 @@
ipv6Loopback = new LinkAddress(addrs.get(0));
}
- assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress());
+ assertEquals(InetAddresses.parseNumericAddress("127.0.0.1"), ipv4Loopback.getAddress());
assertEquals(8, ipv4Loopback.getPrefixLength());
- assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress());
+ assertEquals(InetAddresses.parseNumericAddress("::1"), ipv6Loopback.getAddress());
assertEquals(128, ipv6Loopback.getPrefixLength());
// Null addresses are rejected.
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
index a67156a..a5e44d5 100644
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -53,8 +53,13 @@
assertParcelSane(MatchAllNetworkSpecifier(), 0)
}
- @Test @IgnoreAfter(Build.VERSION_CODES.R)
- fun testCanBeSatisfiedBy_BeforeS() {
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ @IgnoreAfter(Build.VERSION_CODES.R)
+ // Only run this test on Android R.
+ // The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
+ // method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
+ fun testCanBeSatisfiedBy_OnlyForR() {
// MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
// canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
// NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
diff --git a/tests/net/common/java/android/net/NetworkProviderTest.kt b/tests/net/common/java/android/net/NetworkProviderTest.kt
index dd3f5be..77e9f12 100644
--- a/tests/net/common/java/android/net/NetworkProviderTest.kt
+++ b/tests/net/common/java/android/net/NetworkProviderTest.kt
@@ -33,6 +33,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verifyNoMoreInteractions
import java.util.UUID
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
@@ -87,8 +90,8 @@
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
}
- private fun createNetworkProvider(): TestNetworkProvider {
- return TestNetworkProvider(context, mHandlerThread.looper)
+ private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
+ return TestNetworkProvider(ctx, mHandlerThread.looper)
}
@Test
@@ -169,7 +172,12 @@
@Test
fun testDeclareNetworkRequestUnfulfillable() {
- val provider = createNetworkProvider()
+ val mockContext = mock(Context::class.java)
+ val provider = createNetworkProvider(mockContext)
+ // ConnectivityManager not required at creation time
+ verifyNoMoreInteractions(mockContext)
+ doReturn(mCm).`when`(mockContext).getSystemService(Context.CONNECTIVITY_SERVICE)
+
mCm.registerNetworkProvider(provider)
val specifier = StringNetworkSpecifier(UUID.randomUUID().toString())
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index b77ed6a..cade5ba 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -22,10 +22,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.os.Build;
import android.util.SparseArray;
import androidx.test.filters.SmallTest;
-import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
import org.junit.Before;
import org.junit.Test;
@@ -34,7 +37,8 @@
import java.util.ArrayList;
import java.util.List;
-@RunWith(AndroidJUnit4.class)
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
public class OemNetworkPreferencesTest {
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
index 835a83e..c5b25bd 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
@@ -147,5 +147,11 @@
assertEquals(resultData.rcvWndScale, wndScale);
assertEquals(resultData.tos, tos);
assertEquals(resultData.ttl, ttl);
+
+ final String expected = ""
+ + "android.net.TcpKeepalivePacketDataParcelable{srcAddress: [10, 0, 0, 1],"
+ + " srcPort: 1234, dstAddress: [10, 0, 0, 5], dstPort: 4321, seq: 286331153,"
+ + " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
+ assertEquals(expected, resultData.toString());
}
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 6293bef..deda927 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.content.Intent.ACTION_USER_ADDED;
+import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -54,8 +56,10 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
@@ -177,7 +181,6 @@
import android.net.NetworkStackClient;
import android.net.NetworkState;
import android.net.NetworkTestResultParcelable;
-import android.net.NetworkUtils;
import android.net.ProxyInfo;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
@@ -259,7 +262,10 @@
import org.mockito.Spy;
import org.mockito.stubbing.Answer;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -1053,7 +1059,9 @@
public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids);
- updateCapabilitiesInternal(null /* defaultNetwork */, true);
+ if (mAgentRegistered) {
+ mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
+ }
}
public void setVpnType(int vpnType) {
@@ -1079,11 +1087,15 @@
throws Exception {
if (mAgentRegistered) throw new IllegalStateException("already registered");
setUids(uids);
- mConfig.isMetered = isAlwaysMetered;
+ if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
+ verify(mNetworkManagementService, times(1))
+ .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
+ verify(mNetworkManagementService, never())
+ .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
mAgentRegistered = true;
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -1138,28 +1150,6 @@
mMockNetworkAgent.sendLinkProperties(lp);
}
- private NetworkCapabilities updateCapabilitiesInternal(Network defaultNetwork,
- boolean sendToConnectivityService) {
- if (!mAgentRegistered) return null;
- super.updateCapabilities(defaultNetwork);
- // Because super.updateCapabilities will update the capabilities of the agent but
- // not the mock agent, the mock agent needs to know about them.
- copyCapabilitiesToNetworkAgent(sendToConnectivityService);
- return new NetworkCapabilities(mNetworkCapabilities);
- }
-
- private void copyCapabilitiesToNetworkAgent(boolean sendToConnectivityService) {
- if (null != mMockNetworkAgent) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
- sendToConnectivityService);
- }
- }
-
- @Override
- public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
- return updateCapabilitiesInternal(defaultNetwork, false);
- }
-
public void disconnect() {
if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
mAgentRegistered = false;
@@ -1244,7 +1234,7 @@
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
@@ -1967,6 +1957,37 @@
}
@Test
+ public void testOwnerUidCannotChange() throws Exception {
+ // Owner UIDs are not visible without location permission.
+ setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
+ Manifest.permission.ACCESS_FINE_LOCATION);
+
+ final NetworkCapabilities ncTemplate = new NetworkCapabilities();
+ final int originalOwnerUid = Process.myUid();
+ ncTemplate.setOwnerUid(originalOwnerUid);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, new LinkProperties(),
+ ncTemplate);
+ mWiFiNetworkAgent.connect(false);
+ waitForIdle();
+
+ // Send ConnectivityService an update to the mWiFiNetworkAgent's capabilities that changes
+ // the owner UID and an unrelated capability.
+ NetworkCapabilities agentCapabilities = mWiFiNetworkAgent.getNetworkCapabilities();
+ assertEquals(originalOwnerUid, agentCapabilities.getOwnerUid());
+ agentCapabilities.setOwnerUid(42);
+ assertFalse(agentCapabilities.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+ agentCapabilities.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ mWiFiNetworkAgent.setNetworkCapabilities(agentCapabilities, true);
+ waitForIdle();
+
+ // Check that the capability change has been applied but the owner UID is not modified.
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork());
+ assertEquals(originalOwnerUid, nc.getOwnerUid());
+ assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
+ }
+
+ @Test
public void testMultipleLingering() throws Exception {
// This test would be flaky with the default 120ms timer: that is short enough that
// lingered networks are torn down before assertions can be run. We don't want to mock the
@@ -4799,7 +4820,7 @@
lp.setInterfaceName(WIFI_IFNAME);
LinkAddress myIpv4Address = new LinkAddress("192.168.12.3/24");
RouteInfo myIpv4DefaultRoute = new RouteInfo((IpPrefix) null,
- NetworkUtils.numericToInetAddress("192.168.12.1"), lp.getInterfaceName());
+ InetAddresses.parseNumericAddress("192.168.12.1"), lp.getInterfaceName());
lp.addLinkAddress(myIpv4Address);
lp.addRoute(myIpv4DefaultRoute);
@@ -4941,8 +4962,6 @@
final Network[] cellAndVpn = new Network[] {
mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
- Network[] cellAndWifi = new Network[] {
- mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
// A VPN with default (null) underlying networks sets the underlying network's interfaces...
expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
@@ -4952,10 +4971,13 @@
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ final Network[] onlyNull = new Network[]{null};
final Network[] wifiAndVpn = new Network[] {
mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
- cellAndWifi = new Network[] {
+ final Network[] cellAndWifi = new Network[] {
mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
+ final Network[] cellNullAndWifi = new Network[] {
+ mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
@@ -4981,6 +5003,13 @@
new String[]{MOBILE_IFNAME, WIFI_IFNAME});
reset(mStatsService);
+ // Null underlying networks are ignored.
+ mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ reset(mStatsService);
+
// If an underlying network disconnects, that interface should no longer be underlying.
// This doesn't actually work because disconnectAndDestroyNetwork only notifies
// NetworkStatsService before the underlying network is actually removed. So the underlying
@@ -5015,6 +5044,7 @@
argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
&& WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
mEthernetNetworkAgent.disconnect();
+ waitForIdle();
reset(mStatsService);
// When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
@@ -5027,6 +5057,25 @@
waitForIdle();
expectForceUpdateIfaces(wifiAndVpn, null);
reset(mStatsService);
+
+ // Specifying only a null underlying network is the same as no networks.
+ mService.setUnderlyingNetworksForVpn(onlyNull);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, null);
+ reset(mStatsService);
+
+ // Specifying networks that are all disconnected is the same as specifying no networks.
+ mService.setUnderlyingNetworksForVpn(onlyCell);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, null);
+ reset(mStatsService);
+
+ // Passing in null again means follow the default network again.
+ mService.setUnderlyingNetworksForVpn(null);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{WIFI_IFNAME});
+ reset(mStatsService);
}
@Test
@@ -5381,6 +5430,106 @@
}
@Test
+ public void testApplyUnderlyingCapabilities() throws Exception {
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mCellNetworkAgent.connect(false /* validated */);
+ mWiFiNetworkAgent.connect(false /* validated */);
+
+ final NetworkCapabilities cellNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkDownstreamBandwidthKbps(10);
+ final NetworkCapabilities wifiNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .setLinkUpstreamBandwidthKbps(20);
+ mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
+ waitForIdle();
+
+ final Network mobile = mCellNetworkAgent.getNetwork();
+ final Network wifi = mWiFiNetworkAgent.getNetwork();
+
+ final NetworkCapabilities initialCaps = new NetworkCapabilities();
+ initialCaps.addCapability(NET_CAPABILITY_INTERNET);
+ initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
+ withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withNoUnderlying.addTransportType(TRANSPORT_VPN);
+ withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+
+ final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ final NetworkCapabilities withWifiAndMobileUnderlying =
+ new NetworkCapabilities(withNoUnderlying);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+ withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
+ final boolean notDeclaredMetered = false;
+ mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+ assertEquals(withMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ final boolean isDeclaredMetered = true;
+ withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+ }
+
+ @Test
public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
final TestNetworkCallback callback = new TestNetworkCallback();
final NetworkRequest request = new NetworkRequest.Builder()
@@ -5468,6 +5617,7 @@
final Set<UidRange> ranges = uidRangesForUid(uid);
mMockVpn.registerAgent(ranges);
+ mService.setUnderlyingNetworksForVpn(new Network[0]);
// VPN networks do not satisfy the default request and are automatically validated
// by NetworkMonitor
@@ -5476,19 +5626,12 @@
mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
mMockVpn.connect(false);
- mService.setUnderlyingNetworksForVpn(new Network[0]);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
+ genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
- defaultCallback.expectAvailableCallbacksUnvalidated(mMockVpn);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- genericNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
- genericNotVpnNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCapabilitiesThat(mMockVpn, nc -> null == nc.getUids());
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+ vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
@@ -5881,6 +6024,86 @@
}
@Test
+ public void testVpnRestrictedUsers() throws Exception {
+ // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_GRANTED);
+
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Bring up a VPN
+ mMockVpn.establishForMyUid();
+ callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ callback.assertNoCallback();
+
+ final int uid = Process.myUid();
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
+ assertNotNull("nc=" + nc, nc.getUids());
+ assertEquals(nc.getUids(), uidRangesForUid(uid));
+
+ // Set an underlying network and expect to see the VPN transports change.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_WIFI));
+ callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
+ -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
+
+ // Create a fake restricted profile whose parent is our user ID.
+ final int userId = UserHandle.getUserId(uid);
+ final int restrictedUserId = userId + 1;
+ final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
+ info.restrictedProfileParentId = userId;
+ assertTrue(info.isRestricted());
+ when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
+ final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+
+ // Send a USER_ADDED broadcast for it.
+ // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
+ final Handler handler = new Handler(mCsHandlerThread.getLooper());
+ handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+
+ // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
+ // restricted user.
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_WIFI));
+
+ // Change the VPN's capabilities somehow (specifically, disconnect wifi).
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+
+ // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+ handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+
+ // Expect that the VPN gains the UID range for the restricted user, and that the capability
+ // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 1
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+ }
+
+ @Test
public void testIsActiveNetworkMeteredOverWifi() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
@@ -6826,8 +7049,8 @@
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
mMockVpn.establish(lp, VPN_UID, vpnRange);
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
+ // A connected VPN should have interface rules set up. There are two expected invocations,
+ // one during the VPN initial connection, one during the VPN LinkProperties update.
ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
@@ -7342,20 +7565,14 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- // setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
- // active
- final VpnInfo info = new VpnInfo();
- info.ownerUid = Process.myUid();
- info.vpnIface = VPN_IFNAME;
- mMockVpn.setVpnInfo(info);
-
mMockVpn.establishForMyUid();
- waitForIdle();
+ // Wait for networks to connect and broadcasts to be sent before removing permissions.
+ waitForIdle();
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
-
assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+ waitForIdle();
assertTrue(
"Active VPN permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
@@ -7363,6 +7580,7 @@
mContext.getOpPackageName()));
assertTrue(mService.setUnderlyingNetworksForVpn(null));
+ waitForIdle();
assertFalse(
"VPN shouldn't receive callback on non-underlying network",
mService.checkConnectivityDiagnosticsPermissions(
@@ -7585,4 +7803,39 @@
mCm.unregisterNetworkCallback(networkCallback);
}
+
+ @Test
+ public void testDumpDoesNotCrash() {
+ StringWriter stringWriter = new StringWriter();
+
+ mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
+
+ assertFalse(stringWriter.toString().isEmpty());
+ }
+
+ @Test
+ public void testRequestsSortedByIdSortsCorrectly() {
+ final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+
+ ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+
+ assertTrue(nriOutput.length > 1);
+ for (int i = 0; i < nriOutput.length - 1; i++) {
+ boolean isRequestIdInOrder =
+ nriOutput[i].mRequests.get(0).requestId
+ < nriOutput[i + 1].mRequests.get(0).requestId;
+ assertTrue(isRequestIdInOrder);
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 529d03c..799bcc8 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -34,6 +34,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.INetd;
+import android.net.InetAddresses;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
import android.net.IpSecManager;
@@ -44,7 +45,6 @@
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
import android.net.Network;
-import android.net.NetworkUtils;
import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.ParcelFileDescriptor;
@@ -272,7 +272,7 @@
IpSecSpiResponse spi =
mIpSecService.allocateSecurityParameterIndex(
- NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
+ InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
new Binder());
return spi.resourceId;
diff --git a/tests/net/java/com/android/server/NetworkManagementServiceTest.java b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
index 968b307..ea763d2 100644
--- a/tests/net/java/com/android/server/NetworkManagementServiceTest.java
+++ b/tests/net/java/com/android/server/NetworkManagementServiceTest.java
@@ -16,6 +16,12 @@
package com.android.server;
+import static android.util.DebugUtils.valueToString;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -29,15 +35,19 @@
import android.net.INetd;
import android.net.INetdUnsolicitedEventListener;
import android.net.LinkAddress;
+import android.net.NetworkPolicyManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArrayMap;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.app.IBatteryStats;
-import com.android.server.NetworkManagementService.SystemServices;
+import com.android.server.NetworkManagementService.Dependencies;
import com.android.server.net.BaseNetworkObserver;
import org.junit.After;
@@ -49,13 +59,14 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.function.BiFunction;
+
/**
* Tests for {@link NetworkManagementService}.
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkManagementServiceTest {
-
private NetworkManagementService mNMService;
@Mock private Context mContext;
@@ -66,7 +77,9 @@
@Captor
private ArgumentCaptor<INetdUnsolicitedEventListener> mUnsolListenerCaptor;
- private final SystemServices mServices = new SystemServices() {
+ private final MockDependencies mDeps = new MockDependencies();
+
+ private final class MockDependencies extends Dependencies {
@Override
public IBinder getService(String name) {
switch (name) {
@@ -76,14 +89,21 @@
throw new UnsupportedOperationException("Unknown service " + name);
}
}
+
@Override
public void registerLocalService(NetworkManagementInternal nmi) {
}
+
@Override
public INetd getNetd() {
return mNetdService;
}
- };
+
+ @Override
+ public int getCallingUid() {
+ return Process.SYSTEM_UID;
+ }
+ }
@Before
public void setUp() throws Exception {
@@ -91,7 +111,7 @@
doNothing().when(mNetdService)
.registerUnsolicitedEventListener(mUnsolListenerCaptor.capture());
// Start the service and wait until it connects to our socket.
- mNMService = NetworkManagementService.create(mContext, mServices);
+ mNMService = NetworkManagementService.create(mContext, mDeps);
}
@After
@@ -192,4 +212,105 @@
// Make sure nothing else was called.
verifyNoMoreInteractions(observer);
}
+
+ @Test
+ public void testFirewallEnabled() {
+ mNMService.setFirewallEnabled(true);
+ assertTrue(mNMService.isFirewallEnabled());
+
+ mNMService.setFirewallEnabled(false);
+ assertFalse(mNMService.isFirewallEnabled());
+ }
+
+ private static final int TEST_UID = 111;
+
+ @Test
+ public void testNetworkRestrictedDefault() {
+ assertFalse(mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ public void testMeteredNetworkRestrictions() throws RemoteException {
+ // Make sure the mocked netd method returns true.
+ doReturn(true).when(mNetdService).bandwidthEnableDataSaver(anyBoolean());
+
+ // Restrict usage of mobile data in background
+ mNMService.setUidMeteredNetworkDenylist(TEST_UID, true);
+ assertTrue("Should be true since mobile data usage is restricted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setDataSaverModeEnabled(true);
+ verify(mNetdService).bandwidthEnableDataSaver(true);
+
+ mNMService.setUidMeteredNetworkDenylist(TEST_UID, false);
+ assertTrue("Should be true since data saver is on and the uid is not allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ mNMService.setUidMeteredNetworkAllowlist(TEST_UID, true);
+ assertFalse("Should be false since data saver is on and the uid is allowlisted",
+ mNMService.isNetworkRestricted(TEST_UID));
+
+ // remove uid from allowlist and turn datasaver off again
+ mNMService.setUidMeteredNetworkAllowlist(TEST_UID, false);
+ mNMService.setDataSaverModeEnabled(false);
+ verify(mNetdService).bandwidthEnableDataSaver(false);
+ assertFalse("Network should not be restricted when data saver is off",
+ mNMService.isNetworkRestricted(TEST_UID));
+ }
+
+ @Test
+ public void testFirewallChains() {
+ final ArrayMap<Integer, ArrayMap<Integer, Boolean>> expected = new ArrayMap<>();
+ // Dozable chain
+ final ArrayMap<Integer, Boolean> isRestrictedForDozable = new ArrayMap<>();
+ isRestrictedForDozable.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForDozable.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForDozable.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(INetd.FIREWALL_CHAIN_DOZABLE, isRestrictedForDozable);
+ // Powersaver chain
+ final ArrayMap<Integer, Boolean> isRestrictedForPowerSave = new ArrayMap<>();
+ isRestrictedForPowerSave.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForPowerSave.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(INetd.FIREWALL_CHAIN_POWERSAVE, isRestrictedForPowerSave);
+ // Standby chain
+ final ArrayMap<Integer, Boolean> isRestrictedForStandby = new ArrayMap<>();
+ isRestrictedForStandby.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, false);
+ isRestrictedForStandby.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForStandby.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(INetd.FIREWALL_CHAIN_STANDBY, isRestrictedForStandby);
+ // Restricted mode chain
+ final ArrayMap<Integer, Boolean> isRestrictedForRestrictedMode = new ArrayMap<>();
+ isRestrictedForRestrictedMode.put(NetworkPolicyManager.FIREWALL_RULE_DEFAULT, true);
+ isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_ALLOW, false);
+ isRestrictedForRestrictedMode.put(INetd.FIREWALL_RULE_DENY, true);
+ expected.put(INetd.FIREWALL_CHAIN_RESTRICTED, isRestrictedForRestrictedMode);
+
+ final int[] chains = {
+ INetd.FIREWALL_CHAIN_STANDBY,
+ INetd.FIREWALL_CHAIN_POWERSAVE,
+ INetd.FIREWALL_CHAIN_DOZABLE,
+ INetd.FIREWALL_CHAIN_RESTRICTED
+ };
+ final int[] states = {
+ INetd.FIREWALL_RULE_ALLOW,
+ INetd.FIREWALL_RULE_DENY,
+ NetworkPolicyManager.FIREWALL_RULE_DEFAULT
+ };
+ BiFunction<Integer, Integer, String> errorMsg = (chain, state) -> {
+ return String.format("Unexpected value for chain: %s and state: %s",
+ valueToString(INetd.class, "FIREWALL_CHAIN_", chain),
+ valueToString(INetd.class, "FIREWALL_RULE_", state));
+ };
+ for (int chain : chains) {
+ final ArrayMap<Integer, Boolean> expectedValues = expected.get(chain);
+ mNMService.setFirewallChainEnabled(chain, true);
+ for (int state : states) {
+ mNMService.setFirewallUidRule(chain, TEST_UID, state);
+ assertEquals(errorMsg.apply(chain, state),
+ expectedValues.get(state), mNMService.isNetworkRestricted(TEST_UID));
+ }
+ mNMService.setFirewallChainEnabled(chain, false);
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c..de35f91 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -123,7 +123,7 @@
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index a553b58..337507a 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,15 +21,6 @@
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -41,6 +32,7 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -86,10 +78,10 @@
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -100,6 +92,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.server.IpSecService;
@@ -223,6 +216,8 @@
.thenReturn(mNotificationManager);
when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
.thenReturn(mConnectivityManager);
+ when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
@@ -589,7 +584,7 @@
}
@Test
- public void testNotificationShownForAlwaysOnApp() {
+ public void testNotificationShownForAlwaysOnApp() throws Exception {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
@@ -617,103 +612,6 @@
order.verify(mNotificationManager).cancel(anyString(), anyInt());
}
- @Test
- public void testCapabilities() {
- final Vpn vpn = createVpn(primaryUser.id);
- setMockedUsers(primaryUser);
-
- final Network mobile = new Network(1);
- final Network wifi = new Network(2);
-
- final Map<Network, NetworkCapabilities> networks = new HashMap<>();
- networks.put(
- mobile,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(
- wifi,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .setLinkUpstreamBandwidthKbps(20));
- setMockedNetworks(networks);
-
- final NetworkCapabilities caps = new NetworkCapabilities();
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertFalse(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile, wifi},
- caps,
- false /* isAlwaysMetered */);
- assertTrue(caps.hasTransport(TRANSPORT_VPN));
- assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
- assertTrue(caps.hasTransport(TRANSPORT_WIFI));
- assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
- assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- }
-
/**
* The profile name should NOT change between releases for backwards compatibility
*
@@ -1037,7 +935,7 @@
when(exception.getErrorType())
.thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1048,20 +946,20 @@
ikeCb.onClosedExceptionally(exception);
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
@Test
public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
.thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1100,8 +998,7 @@
// a subsequent CL.
}
- public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
+ private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
setMockedUsers(primaryUser);
// Dummy egress interface
@@ -1118,7 +1015,7 @@
@Test
public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(mVpnProfile);
+ startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
// a subsequent patch.
}
@@ -1153,7 +1050,7 @@
legacyRunnerReady.open();
return new Network(102);
});
- final Vpn vpn = startLegacyVpn(profile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
// udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1287,8 +1184,13 @@
doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
.thenReturn(asUserContext);
- return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
+ final TestLooper testLooper = new TestLooper();
+ final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+ verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+ provider -> provider.getName().contains("VpnNetworkProvider")
+ ));
+ return vpn;
}
private static void assertBlocked(Vpn vpn, int... uids) {
@@ -1318,15 +1220,14 @@
* @see UserManagerService#getUsers(boolean)
*/
doAnswer(invocation -> {
- final boolean excludeDying = (boolean) invocation.getArguments()[0];
final ArrayList<UserInfo> result = new ArrayList<>(users.length);
for (UserInfo ui : users) {
- if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
+ if (ui.isEnabled() && !ui.partial) {
result.add(ui);
}
}
return result;
- }).when(mUserManager).getUsers(anyBoolean());
+ }).when(mUserManager).getAliveUsers();
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];