Merge changes I3b16caad,Iaf5ea7ab,I09a94042,I69a39039,I35300309, ...
* changes:
Let network requests see VPNs.
Move constants into a new file.
Make sure listen requests from VPN apps see their own networks
Add a test for new UID checking code.
Remove UID_RANGES_ADDED and REMOVED.
Move VPN allowed UIDs into NetworkCapabilities.
Pre-import to remove a conflict.
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 2dacf8f..52a2354 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -17,6 +17,7 @@
package android.net;
import android.content.Context;
+import android.net.ConnectivityManager.PacketKeepalive;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -26,7 +27,6 @@
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
-import android.net.ConnectivityManager.PacketKeepalive;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -101,20 +101,6 @@
public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
/**
- * Sent by the NetworkAgent to ConnectivityService to add new UID ranges
- * to be forced into this Network. For VPNs only.
- * obj = UidRange[] to forward
- */
- public static final int EVENT_UID_RANGES_ADDED = BASE + 5;
-
- /**
- * Sent by the NetworkAgent to ConnectivityService to remove UID ranges
- * from being forced into this Network. For VPNs only.
- * obj = UidRange[] to stop forwarding
- */
- public static final int EVENT_UID_RANGES_REMOVED = BASE + 6;
-
- /**
* 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.
@@ -390,22 +376,6 @@
}
/**
- * Called by the VPN code when it wants to add ranges of UIDs to be routed
- * through the VPN network.
- */
- public void addUidRanges(UidRange[] ranges) {
- queueOrSendMessage(EVENT_UID_RANGES_ADDED, ranges);
- }
-
- /**
- * Called by the VPN code when it wants to remove ranges of UIDs from being routed
- * through the VPN network.
- */
- public void removeUidRanges(UidRange[] ranges) {
- queueOrSendMessage(EVENT_UID_RANGES_REMOVED, ranges);
- }
-
- /**
* Called by the bearer to indicate this network was manually selected by the user.
* This should be called before the NetworkInfo is marked CONNECTED so that this
* Network can be given special treatment at that time. If {@code acceptUnvalidated} is
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index be85583..31516fd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -20,6 +20,8 @@
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArraySet;
+import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
@@ -28,6 +30,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
+import java.util.Set;
import java.util.StringJoiner;
/**
@@ -46,6 +49,7 @@
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
+ private static final int INVALID_UID = -1;
/**
* @hide
@@ -63,6 +67,8 @@
mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
mNetworkSpecifier = nc.mNetworkSpecifier;
mSignalStrength = nc.mSignalStrength;
+ mUids = nc.mUids;
+ mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
}
}
@@ -76,6 +82,8 @@
mLinkUpBandwidthKbps = mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
mNetworkSpecifier = null;
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
+ mUids = null;
+ mEstablishingVpnAppUid = INVALID_UID;
}
/**
@@ -618,6 +626,29 @@
}
/**
+ * UID of the app that manages this network, or INVALID_UID if none/unknown.
+ *
+ * This field keeps track of the UID of the app that created this network and is in charge
+ * of managing it. In the practice, it is used to store the UID of VPN apps so it is named
+ * accordingly, but it may be renamed if other mechanisms are offered for third party apps
+ * to create networks.
+ *
+ * Because this field is only used in the services side (and to avoid apps being able to
+ * set this to whatever they want), this field is not parcelled and will not be conserved
+ * across the IPC boundary.
+ * @hide
+ */
+ private int mEstablishingVpnAppUid = INVALID_UID;
+
+ /**
+ * Set the UID of the managing app.
+ * @hide
+ */
+ public void setEstablishingVpnAppUid(final int uid) {
+ mEstablishingVpnAppUid = uid;
+ }
+
+ /**
* Value indicating that link bandwidth is unspecified.
* @hide
*/
@@ -836,6 +867,174 @@
}
/**
+ * List of UIDs this network applies to. No restriction if null.
+ * <p>
+ * This is typically (and at this time, only) used by VPN. This network is only available to
+ * the UIDs in this list, and it is their default network. Apps in this list that wish to
+ * bypass the VPN can do so iff the VPN app allows them to or if they are privileged. If this
+ * member is null, then the network is not restricted by app UID. If it's an empty list, then
+ * it means nobody can use it.
+ * As a special exception, the app managing this network (as identified by its UID stored in
+ * mEstablishingVpnAppUid) can always see this network. This is embodied by a special check in
+ * satisfiedByUids. That still does not mean the network necessarily <strong>applies</strong>
+ * to the app that manages it as determined by #appliesToUid.
+ * <p>
+ * Please note that in principle a single app can be associated with multiple UIDs because
+ * each app will have a different UID when it's run as a different (macro-)user. A single
+ * macro user can only have a single active VPN app at any given time however.
+ * <p>
+ * Also please be aware this class does not try to enforce any normalization on this. Callers
+ * can only alter the UIDs by setting them wholesale : this class does not provide any utility
+ * to add or remove individual UIDs or ranges. If callers have any normalization needs on
+ * their own (like requiring sortedness or no overlap) they need to enforce it
+ * themselves. Some of the internal methods also assume this is normalized as in no adjacent
+ * or overlapping ranges are present.
+ *
+ * @hide
+ */
+ private Set<UidRange> mUids = null;
+
+ /**
+ * Convenience method to set the UIDs this network applies to to a single UID.
+ * @hide
+ */
+ public NetworkCapabilities setSingleUid(int uid) {
+ final ArraySet<UidRange> identity = new ArraySet<>(1);
+ identity.add(new UidRange(uid, uid));
+ setUids(identity);
+ return this;
+ }
+
+ /**
+ * Set the list of UIDs this network applies to.
+ * This makes a copy of the set so that callers can't modify it after the call.
+ * @hide
+ */
+ public NetworkCapabilities setUids(Set<UidRange> uids) {
+ if (null == uids) {
+ mUids = null;
+ } else {
+ mUids = new ArraySet<>(uids);
+ }
+ return this;
+ }
+
+ /**
+ * Get the list of UIDs this network applies to.
+ * This returns a copy of the set so that callers can't modify the original object.
+ * @hide
+ */
+ public Set<UidRange> getUids() {
+ return null == mUids ? null : new ArraySet<>(mUids);
+ }
+
+ /**
+ * Test whether this network applies to this UID.
+ * @hide
+ */
+ public boolean appliesToUid(int uid) {
+ if (null == mUids) return true;
+ for (UidRange range : mUids) {
+ if (range.contains(uid)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests if the set of UIDs that this network applies to is the same of the passed set of UIDs.
+ * <p>
+ * This test only checks whether equal range objects are in both sets. It will
+ * return false if the ranges are not exactly the same, even if the covered UIDs
+ * are for an equivalent result.
+ * <p>
+ * Note that this method is not very optimized, which is fine as long as it's not used very
+ * often.
+ * <p>
+ * nc is assumed nonnull.
+ *
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean equalsUids(NetworkCapabilities nc) {
+ Set<UidRange> comparedUids = nc.mUids;
+ if (null == comparedUids) return null == mUids;
+ if (null == mUids) return false;
+ // Make a copy so it can be mutated to check that all ranges in mUids
+ // also are in uids.
+ final Set<UidRange> uids = new ArraySet<>(mUids);
+ for (UidRange range : comparedUids) {
+ if (!uids.contains(range)) {
+ return false;
+ }
+ uids.remove(range);
+ }
+ return uids.isEmpty();
+ }
+
+ /**
+ * Test whether the passed NetworkCapabilities satisfies the UIDs this capabilities require.
+ *
+ * This method is called on the NetworkCapabilities embedded in a request with the
+ * capabilities of an available network. It checks whether all the UIDs from this listen
+ * (representing the UIDs that must have access to the network) are satisfied by the UIDs
+ * in the passed nc (representing the UIDs that this network is available to).
+ * <p>
+ * As a special exception, the UID that created the passed network (as represented by its
+ * mEstablishingVpnAppUid field) always satisfies a NetworkRequest requiring it (of LISTEN
+ * or REQUEST types alike), even if the network does not apply to it. That is so a VPN app
+ * can see its own network when it listens for it.
+ * <p>
+ * nc is assumed nonnull. Else, NPE.
+ * @see #appliesToUid
+ * @hide
+ */
+ public boolean satisfiedByUids(NetworkCapabilities nc) {
+ if (null == nc.mUids) return true; // The network satisfies everything.
+ if (null == mUids) return false; // Not everything allowed but requires everything
+ for (UidRange requiredRange : mUids) {
+ if (requiredRange.contains(nc.mEstablishingVpnAppUid)) return true;
+ if (!nc.appliesToUidRange(requiredRange)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether this network applies to the passed ranges.
+ * This assumes that to apply, the passed range has to be entirely contained
+ * within one of the ranges this network applies to. If the ranges are not normalized,
+ * this method may return false even though all required UIDs are covered because no
+ * single range contained them all.
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean appliesToUidRange(UidRange requiredRange) {
+ if (null == mUids) return true;
+ for (UidRange uidRange : mUids) {
+ if (uidRange.containsRange(requiredRange)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Combine the UIDs this network currently applies to with the UIDs the passed
+ * NetworkCapabilities apply to.
+ * nc is assumed nonnull.
+ */
+ private void combineUids(NetworkCapabilities nc) {
+ if (null == nc.mUids || null == mUids) {
+ mUids = null;
+ return;
+ }
+ mUids.addAll(nc.mUids);
+ }
+
+ /**
* Combine a set of Capabilities to this one. Useful for coming up with the complete set
* @hide
*/
@@ -845,6 +1044,7 @@
combineLinkBandwidths(nc);
combineSpecifiers(nc);
combineSignalStrength(nc);
+ combineUids(nc);
}
/**
@@ -857,12 +1057,13 @@
* @hide
*/
private boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc, boolean onlyImmutable) {
- return (nc != null &&
- satisfiedByNetCapabilities(nc, onlyImmutable) &&
- satisfiedByTransportTypes(nc) &&
- (onlyImmutable || satisfiedByLinkBandwidths(nc)) &&
- satisfiedBySpecifier(nc) &&
- (onlyImmutable || satisfiedBySignalStrength(nc)));
+ return (nc != null
+ && satisfiedByNetCapabilities(nc, onlyImmutable)
+ && satisfiedByTransportTypes(nc)
+ && (onlyImmutable || satisfiedByLinkBandwidths(nc))
+ && satisfiedBySpecifier(nc)
+ && (onlyImmutable || satisfiedBySignalStrength(nc))
+ && (onlyImmutable || satisfiedByUids(nc)));
}
/**
@@ -945,24 +1146,26 @@
@Override
public boolean equals(Object obj) {
if (obj == null || (obj instanceof NetworkCapabilities == false)) return false;
- NetworkCapabilities that = (NetworkCapabilities)obj;
- return (equalsNetCapabilities(that) &&
- equalsTransportTypes(that) &&
- equalsLinkBandwidths(that) &&
- equalsSignalStrength(that) &&
- equalsSpecifier(that));
+ NetworkCapabilities that = (NetworkCapabilities) obj;
+ return (equalsNetCapabilities(that)
+ && equalsTransportTypes(that)
+ && equalsLinkBandwidths(that)
+ && equalsSignalStrength(that)
+ && equalsSpecifier(that)
+ && equalsUids(that));
}
@Override
public int hashCode() {
- return ((int)(mNetworkCapabilities & 0xFFFFFFFF) +
- ((int)(mNetworkCapabilities >> 32) * 3) +
- ((int)(mTransportTypes & 0xFFFFFFFF) * 5) +
- ((int)(mTransportTypes >> 32) * 7) +
- (mLinkUpBandwidthKbps * 11) +
- (mLinkDownBandwidthKbps * 13) +
- Objects.hashCode(mNetworkSpecifier) * 17 +
- (mSignalStrength * 19));
+ return ((int) (mNetworkCapabilities & 0xFFFFFFFF)
+ + ((int) (mNetworkCapabilities >> 32) * 3)
+ + ((int) (mTransportTypes & 0xFFFFFFFF) * 5)
+ + ((int) (mTransportTypes >> 32) * 7)
+ + (mLinkUpBandwidthKbps * 11)
+ + (mLinkDownBandwidthKbps * 13)
+ + Objects.hashCode(mNetworkSpecifier) * 17
+ + (mSignalStrength * 19)
+ + Objects.hashCode(mUids) * 23);
}
@Override
@@ -977,6 +1180,7 @@
dest.writeInt(mLinkDownBandwidthKbps);
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
dest.writeInt(mSignalStrength);
+ dest.writeArraySet(new ArraySet<>(mUids));
}
public static final Creator<NetworkCapabilities> CREATOR =
@@ -991,6 +1195,8 @@
netCap.mLinkDownBandwidthKbps = in.readInt();
netCap.mNetworkSpecifier = in.readParcelable(null);
netCap.mSignalStrength = in.readInt();
+ netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
+ null /* ClassLoader, null for default */);
return netCap;
}
@Override
@@ -1023,7 +1229,12 @@
String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : "");
- return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
+ String uids = (null != mUids ? " Uids: <" + mUids + ">" : "");
+
+ String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid;
+
+ return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength
+ + uids + establishingAppUid + "]";
}
/**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ea6bc17..6dbf538 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@
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_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -105,6 +106,7 @@
import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.LocalLog;
import android.util.LocalLog.ReadOnlyLocalLog;
import android.util.Log;
@@ -174,6 +176,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
@@ -709,12 +712,12 @@
mSystemProperties = getSystemProperties();
mMetricsLog = logger;
- mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
+ mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
mNetworkRequests.put(mDefaultRequest, defaultNRI);
mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
- mDefaultMobileDataRequest = createInternetRequestForTransport(
+ mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
mHandlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -879,7 +882,7 @@
deps);
}
- private NetworkRequest createInternetRequestForTransport(
+ private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1257,7 +1260,11 @@
for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network);
nc = getNetworkCapabilitiesInternal(nai);
+ // nc is a copy of the capabilities in nai, so it's fine to mutate it
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
if (nc != null) {
+ nc.setSingleUid(userId);
result.put(network, nc);
}
}
@@ -2050,24 +2057,6 @@
if (score != null) updateNetworkScore(nai, score.intValue());
break;
}
- case NetworkAgent.EVENT_UID_RANGES_ADDED: {
- try {
- mNetd.addVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
- } catch (Exception e) {
- // Never crash!
- loge("Exception in addVpnUidRanges: " + e);
- }
- break;
- }
- case NetworkAgent.EVENT_UID_RANGES_REMOVED: {
- try {
- mNetd.removeVpnUidRanges(nai.network.netId, (UidRange[])msg.obj);
- } catch (Exception e) {
- // Never crash!
- loge("Exception in removeVpnUidRanges: " + e);
- }
- break;
- }
case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: {
if (nai.everConnected && !nai.networkMisc.explicitlySelected) {
loge("ERROR: already-connected network explicitly selected.");
@@ -4206,6 +4195,7 @@
// the system default network.
if (type == NetworkRequest.Type.TRACK_DEFAULT) {
networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
+ networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
enforceAccessPermission();
} else {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4216,6 +4206,13 @@
enforceMeteredApnPolicy(networkCapabilities);
}
ensureRequestableCapabilities(networkCapabilities);
+ // Set the UID range for this request to the single UID of the requester.
+ // This will overwrite any allowed UIDs in the requested capabilities. Though there
+ // are no visible methods to set the UIDs, an app could use reflection to try and get
+ // networks for other apps so it's essential that the UIDs are overwritten.
+ // TODO : don't forcefully set the UID when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ networkCapabilities.setSingleUid(Binder.getCallingUid());
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -4289,6 +4286,9 @@
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
ensureValidNetworkSpecifier(networkCapabilities);
+ // TODO : don't forcefully set the UID when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ networkCapabilities.setSingleUid(Binder.getCallingUid());
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4342,6 +4342,9 @@
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ // TODO : don't forcefully set the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(Binder.getCallingUid());
if (!ConnectivityManager.checkChangePermission(mContext)) {
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4370,8 +4373,12 @@
}
ensureValidNetworkSpecifier(networkCapabilities);
- NetworkRequest networkRequest = new NetworkRequest(
- new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
+ final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ // TODO : don't forcefully set the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(Binder.getCallingUid());
+
+ NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
if (VDBG) log("pendingListenForNetwork for " + nri);
@@ -4514,6 +4521,7 @@
NetworkInfo networkInfo = na.networkInfo;
na.networkInfo = null;
updateNetworkInfo(na, networkInfo);
+ updateUids(na, null, na.networkCapabilities);
}
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
@@ -4762,6 +4770,8 @@
nai.networkCapabilities = newNc;
}
+ updateUids(nai, prevNc, newNc);
+
if (nai.getCurrentScore() == oldScore && newNc.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
// the change we're processing can't affect any requests, it can only affect the listens
@@ -4798,6 +4808,34 @@
}
}
+ private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
+ NetworkCapabilities newNc) {
+ Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
+ Set<UidRange> newRanges = null == newNc ? null : newNc.getUids();
+ if (null == prevRanges) prevRanges = new ArraySet<>();
+ if (null == newRanges) newRanges = new ArraySet<>();
+ final Set<UidRange> prevRangesCopy = new ArraySet<>(prevRanges);
+
+ prevRanges.removeAll(newRanges);
+ newRanges.removeAll(prevRangesCopy);
+
+ try {
+ if (!newRanges.isEmpty()) {
+ final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
+ newRanges.toArray(addedRangesArray);
+ mNetd.addVpnUidRanges(nai.network.netId, addedRangesArray);
+ }
+ if (!prevRanges.isEmpty()) {
+ final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
+ prevRanges.toArray(removedRangesArray);
+ mNetd.removeVpnUidRanges(nai.network.netId, removedRangesArray);
+ }
+ } catch (Exception e) {
+ // Never crash!
+ loge("Exception in updateUids: " + e);
+ }
+ }
+
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
if (mNetworkForNetId.get(nai.network.netId) != nai) {
// Ignore updates for disconnected networks
@@ -4889,7 +4927,12 @@
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
- putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+ final NetworkCapabilities nc =
+ new NetworkCapabilities(networkAgent.networkCapabilities);
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(nri.mUid);
+ putParcelable(bundle, nc);
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
@@ -5413,6 +5456,7 @@
}
}
}
+ updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
} else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
state == NetworkInfo.State.SUSPENDED) {
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
new file mode 100644
index 0000000..24865bc
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+/**
+ * A class encapsulating various constants used by Connectivity.
+ * @hide
+ */
+public class ConnectivityConstants {
+ // IPC constants
+ public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
+ "android.net.conn.NETWORK_CONDITIONS_MEASURED";
+ public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
+ public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
+ public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
+ public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
+ public static final String EXTRA_CELL_ID = "extra_cellid";
+ public static final String EXTRA_SSID = "extra_ssid";
+ public static final String EXTRA_BSSID = "extra_bssid";
+ /** real time since boot */
+ public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
+ public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
+
+ public static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
+ "android.permission.ACCESS_NETWORK_CONDITIONS";
+
+ // Penalty applied to scores of Networks that have not been validated.
+ public static final int UNVALIDATED_SCORE_PENALTY = 40;
+
+ // Score for explicitly connected network.
+ //
+ // This ensures that a) the explicitly selected network is never trumped by anything else, and
+ // b) the explicitly selected network is never torn down.
+ public static final int MAXIMUM_NETWORK_SCORE = 100;
+ // VPNs typically have priority over other networks. Give them a score that will
+ // let them win every single time.
+ public static final int VPN_DEFAULT_SCORE = 101;
+}
diff --git a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
index 2ccfdd1..f6b73b7 100644
--- a/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
+++ b/services/core/java/com/android/server/connectivity/KeepalivePacketData.java
@@ -16,6 +16,9 @@
package com.android.server.connectivity;
+import static android.net.util.NetworkConstants.IPV4_HEADER_MIN_LEN;
+import static android.net.util.NetworkConstants.UDP_HEADER_LEN;
+
import android.system.OsConstants;
import android.net.ConnectivityManager;
import android.net.NetworkUtils;
@@ -57,9 +60,6 @@
/** Packet data. A raw byte string of packet data, not including the link-layer header. */
public final byte[] data;
- private static final int IPV4_HEADER_LENGTH = 20;
- private static final int UDP_HEADER_LENGTH = 8;
-
protected KeepalivePacketData(InetAddress srcAddress, int srcPort,
InetAddress dstAddress, int dstPort, byte[] data) throws InvalidPacketException {
this.srcAddress = srcAddress;
@@ -111,7 +111,7 @@
throw new InvalidPacketException(ERROR_INVALID_PORT);
}
- int length = IPV4_HEADER_LENGTH + UDP_HEADER_LENGTH + 1;
+ int length = IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + 1;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.BIG_ENDIAN);
buf.putShort((short) 0x4500); // IP version and TOS
@@ -130,7 +130,7 @@
buf.putShort((short) 0); // UDP checksum
buf.put((byte) 0xff); // NAT-T keepalive
buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
- buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_LENGTH));
+ buf.putShort(udpChecksumOffset, IpUtils.udpChecksum(buf, 0, IPV4_HEADER_MIN_LEN));
return new KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, buf.array());
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a4d7242..85b70ca 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -223,14 +223,6 @@
// This represents the last score received from the NetworkAgent.
private int currentScore;
- // Penalty applied to scores of Networks that have not been validated.
- private static final int UNVALIDATED_SCORE_PENALTY = 40;
-
- // Score for explicitly connected network.
- //
- // This ensures that a) the explicitly selected network is never trumped by anything else, and
- // b) the explicitly selected network is never torn down.
- private static final int MAXIMUM_NETWORK_SCORE = 100;
// The list of NetworkRequests being satisfied by this Network.
private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
@@ -428,12 +420,12 @@
// down an explicitly selected network before the user gets a chance to prefer it when
// a higher-scoring network (e.g., Ethernet) is available.
if (networkMisc.explicitlySelected && (networkMisc.acceptUnvalidated || pretendValidated)) {
- return MAXIMUM_NETWORK_SCORE;
+ return ConnectivityConstants.MAXIMUM_NETWORK_SCORE;
}
int score = currentScore;
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty()) {
- score -= UNVALIDATED_SCORE_PENALTY;
+ score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
if (score < 0) score = 0;
return score;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 85d1d1e..c471f0c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -24,6 +24,7 @@
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.TrafficStats;
+import android.net.util.NetworkConstants;
import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
@@ -421,8 +422,6 @@
private class IcmpCheck extends SimpleSocketCheck implements Runnable {
private static final int TIMEOUT_SEND = 100;
private static final int TIMEOUT_RECV = 300;
- private static final int ICMPV4_ECHO_REQUEST = 8;
- private static final int ICMPV6_ECHO_REQUEST = 128;
private static final int PACKET_BUFSIZE = 512;
private final int mProtocol;
private final int mIcmpType;
@@ -432,11 +431,11 @@
if (mAddressFamily == AF_INET6) {
mProtocol = IPPROTO_ICMPV6;
- mIcmpType = ICMPV6_ECHO_REQUEST;
+ mIcmpType = NetworkConstants.ICMPV6_ECHO_REQUEST_TYPE;
mMeasurement.description = "ICMPv6";
} else {
mProtocol = IPPROTO_ICMP;
- mIcmpType = ICMPV4_ECHO_REQUEST;
+ mIcmpType = NetworkConstants.ICMPV4_ECHO_REQUEST_TYPE;
mMeasurement.description = "ICMPv4";
}
@@ -504,7 +503,6 @@
private class DnsUdpCheck extends SimpleSocketCheck implements Runnable {
private static final int TIMEOUT_SEND = 100;
private static final int TIMEOUT_RECV = 500;
- private static final int DNS_SERVER_PORT = 53;
private static final int RR_TYPE_A = 1;
private static final int RR_TYPE_AAAA = 28;
private static final int PACKET_BUFSIZE = 512;
@@ -546,7 +544,8 @@
}
try {
- setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV, DNS_SERVER_PORT);
+ setupSocket(SOCK_DGRAM, IPPROTO_UDP, TIMEOUT_SEND, TIMEOUT_RECV,
+ NetworkConstants.DNS_SERVER_PORT);
} catch (ErrnoException | IOException e) {
mMeasurement.recordFailure(e.toString());
return;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index ed26858..8a2e71c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -122,22 +122,6 @@
}
}
- public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
- "android.net.conn.NETWORK_CONDITIONS_MEASURED";
- public static final String EXTRA_CONNECTIVITY_TYPE = "extra_connectivity_type";
- public static final String EXTRA_NETWORK_TYPE = "extra_network_type";
- public static final String EXTRA_RESPONSE_RECEIVED = "extra_response_received";
- public static final String EXTRA_IS_CAPTIVE_PORTAL = "extra_is_captive_portal";
- public static final String EXTRA_CELL_ID = "extra_cellid";
- public static final String EXTRA_SSID = "extra_ssid";
- public static final String EXTRA_BSSID = "extra_bssid";
- /** real time since boot */
- public static final String EXTRA_REQUEST_TIMESTAMP_MS = "extra_request_timestamp_ms";
- public static final String EXTRA_RESPONSE_TIMESTAMP_MS = "extra_response_timestamp_ms";
-
- private static final String PERMISSION_ACCESS_NETWORK_CONDITIONS =
- "android.permission.ACCESS_NETWORK_CONDITIONS";
-
// After a network has been tested this result can be sent with EVENT_NETWORK_TESTED.
// The network should be used as a default internet connection. It was found to be:
// 1. a functioning network providing internet access, or
@@ -1136,7 +1120,8 @@
return;
}
- Intent latencyBroadcast = new Intent(ACTION_NETWORK_CONDITIONS_MEASURED);
+ Intent latencyBroadcast =
+ new Intent(ConnectivityConstants.ACTION_NETWORK_CONDITIONS_MEASURED);
switch (mNetworkAgentInfo.networkInfo.getType()) {
case ConnectivityManager.TYPE_WIFI:
WifiInfo currentWifiInfo = mWifiManager.getConnectionInfo();
@@ -1148,15 +1133,18 @@
// not change it here as it would become impossible to tell whether the SSID is
// simply being surrounded by quotes due to the API, or whether those quotes
// are actually part of the SSID.
- latencyBroadcast.putExtra(EXTRA_SSID, currentWifiInfo.getSSID());
- latencyBroadcast.putExtra(EXTRA_BSSID, currentWifiInfo.getBSSID());
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_SSID,
+ currentWifiInfo.getSSID());
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_BSSID,
+ currentWifiInfo.getBSSID());
} else {
if (VDBG) logw("network info is TYPE_WIFI but no ConnectionInfo found");
return;
}
break;
case ConnectivityManager.TYPE_MOBILE:
- latencyBroadcast.putExtra(EXTRA_NETWORK_TYPE, mTelephonyManager.getNetworkType());
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_NETWORK_TYPE,
+ mTelephonyManager.getNetworkType());
List<CellInfo> info = mTelephonyManager.getAllCellInfo();
if (info == null) return;
int numRegisteredCellInfo = 0;
@@ -1170,16 +1158,16 @@
}
if (cellInfo instanceof CellInfoCdma) {
CellIdentityCdma cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoGsm) {
CellIdentityGsm cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoLte) {
CellIdentityLte cellId = ((CellInfoLte) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
} else if (cellInfo instanceof CellInfoWcdma) {
CellIdentityWcdma cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
- latencyBroadcast.putExtra(EXTRA_CELL_ID, cellId);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CELL_ID, cellId);
} else {
if (VDBG) logw("Registered cellinfo is unrecognized");
return;
@@ -1190,16 +1178,21 @@
default:
return;
}
- latencyBroadcast.putExtra(EXTRA_CONNECTIVITY_TYPE, mNetworkAgentInfo.networkInfo.getType());
- latencyBroadcast.putExtra(EXTRA_RESPONSE_RECEIVED, responseReceived);
- latencyBroadcast.putExtra(EXTRA_REQUEST_TIMESTAMP_MS, requestTimestampMs);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_CONNECTIVITY_TYPE,
+ mNetworkAgentInfo.networkInfo.getType());
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_RECEIVED,
+ responseReceived);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_REQUEST_TIMESTAMP_MS,
+ requestTimestampMs);
if (responseReceived) {
- latencyBroadcast.putExtra(EXTRA_IS_CAPTIVE_PORTAL, isCaptivePortal);
- latencyBroadcast.putExtra(EXTRA_RESPONSE_TIMESTAMP_MS, responseTimestampMs);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_IS_CAPTIVE_PORTAL,
+ isCaptivePortal);
+ latencyBroadcast.putExtra(ConnectivityConstants.EXTRA_RESPONSE_TIMESTAMP_MS,
+ responseTimestampMs);
}
mContext.sendBroadcastAsUser(latencyBroadcast, UserHandle.CURRENT,
- PERMISSION_ACCESS_NETWORK_CONDITIONS);
+ ConnectivityConstants.PERMISSION_ACCESS_NETWORK_CONDITIONS);
}
private void logNetworkEvent(int evtype) {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index d56fb1a..3a27fcb3 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -54,12 +54,12 @@
* @hide
*/
public class PacManager {
- public static final String PAC_PACKAGE = "com.android.pacprocessor";
- public static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
- public static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
+ private static final String PAC_PACKAGE = "com.android.pacprocessor";
+ private static final String PAC_SERVICE = "com.android.pacprocessor.PacService";
+ private static final String PAC_SERVICE_NAME = "com.android.net.IProxyService";
- public static final String PROXY_PACKAGE = "com.android.proxyhandler";
- public static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
+ private static final String PROXY_PACKAGE = "com.android.proxyhandler";
+ private static final String PROXY_SERVICE = "com.android.proxyhandler.ProxyService";
private static final String TAG = "PacManager";
@@ -71,8 +71,6 @@
private static final int DELAY_LONG = 4;
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
- /** Keep these values up-to-date with ProxyService.java */
- public static final String KEY_PROXY = "keyProxy";
private String mCurrentPac;
@GuardedBy("mProxyLock")
private volatile Uri mPacUrl = Uri.EMPTY;
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index aa174e3..bb46d5e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -164,19 +164,6 @@
private boolean mLockdown = false;
/**
- * List of UIDs that are set to use this VPN by default. Normally, every UID in the user is
- * added to this set but that can be changed by adding allowed or disallowed applications. It
- * is non-null iff the VPN is connected.
- *
- * Unless the VPN has set allowBypass=true, these UIDs are forced into the VPN.
- *
- * @see VpnService.Builder#addAllowedApplication(String)
- * @see VpnService.Builder#addDisallowedApplication(String)
- */
- @GuardedBy("this")
- private Set<UidRange> mVpnUsers = null;
-
- /**
* List of UIDs for which networking should be blocked until VPN is ready, during brief periods
* when VPN is not running. For example, during system startup or after a crash.
* @see mLockdown
@@ -688,7 +675,7 @@
agentDisconnect();
jniReset(mInterface);
mInterface = null;
- mVpnUsers = null;
+ mNetworkCapabilities.setUids(null);
}
// Revoke the connection or stop LegacyVpnRunner.
@@ -857,10 +844,14 @@
NetworkMisc networkMisc = new NetworkMisc();
networkMisc.allowBypass = mConfig.allowBypass && !mLockdown;
+ mNetworkCapabilities.setEstablishingVpnAppUid(Binder.getCallingUid());
+ mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserHandle,
+ mConfig.allowedApplications, mConfig.disallowedApplications));
long token = Binder.clearCallingIdentity();
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
- mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) {
+ mNetworkInfo, mNetworkCapabilities, lp,
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {
@Override
public void unwanted() {
// We are user controlled, not driven by NetworkRequest.
@@ -869,11 +860,6 @@
} finally {
Binder.restoreCallingIdentity(token);
}
-
- mVpnUsers = createUserAndRestrictedProfilesRanges(mUserHandle,
- mConfig.allowedApplications, mConfig.disallowedApplications);
- mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
-
mNetworkInfo.setIsAvailable(true);
updateState(DetailedState.CONNECTED, "agentConnect");
}
@@ -953,7 +939,7 @@
Connection oldConnection = mConnection;
NetworkAgent oldNetworkAgent = mNetworkAgent;
mNetworkAgent = null;
- Set<UidRange> oldUsers = mVpnUsers;
+ Set<UidRange> oldUsers = mNetworkCapabilities.getUids();
// Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
@@ -1011,7 +997,7 @@
// restore old state
mConfig = oldConfig;
mConnection = oldConnection;
- mVpnUsers = oldUsers;
+ mNetworkCapabilities.setUids(oldUsers);
mNetworkAgent = oldNetworkAgent;
mInterface = oldInterface;
throw e;
@@ -1131,10 +1117,12 @@
// Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that
// apply to userHandle.
- private List<UidRange> uidRangesForUser(int userHandle) {
+ static private List<UidRange> uidRangesForUser(int userHandle, Set<UidRange> existingRanges) {
+ // UidRange#createForUser returns the entire range of UIDs available to a macro-user.
+ // This is something like 0-99999 ; {@see UserHandle#PER_USER_RANGE}
final UidRange userRange = UidRange.createForUser(userHandle);
final List<UidRange> ranges = new ArrayList<UidRange>();
- for (UidRange range : mVpnUsers) {
+ for (UidRange range : existingRanges) {
if (userRange.containsRange(range)) {
ranges.add(range);
}
@@ -1142,30 +1130,18 @@
return ranges;
}
- private void removeVpnUserLocked(int userHandle) {
- if (mVpnUsers == null) {
- throw new IllegalStateException("VPN is not active");
- }
- final List<UidRange> ranges = uidRangesForUser(userHandle);
- if (mNetworkAgent != null) {
- mNetworkAgent.removeUidRanges(ranges.toArray(new UidRange[ranges.size()]));
- }
- mVpnUsers.removeAll(ranges);
- }
-
public void onUserAdded(int userHandle) {
// If the user is restricted tie them to the parent user's VPN
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
synchronized(Vpn.this) {
- if (mVpnUsers != null) {
+ final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+ if (existingRanges != null) {
try {
- addUserToRanges(mVpnUsers, userHandle, mConfig.allowedApplications,
+ addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications,
mConfig.disallowedApplications);
- if (mNetworkAgent != null) {
- final List<UidRange> ranges = uidRangesForUser(userHandle);
- mNetworkAgent.addUidRanges(ranges.toArray(new UidRange[ranges.size()]));
- }
+ mNetworkCapabilities.setUids(existingRanges);
+ updateCapabilities();
} catch (Exception e) {
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
@@ -1180,9 +1156,14 @@
UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
synchronized(Vpn.this) {
- if (mVpnUsers != null) {
+ final Set<UidRange> existingRanges = mNetworkCapabilities.getUids();
+ if (existingRanges != null) {
try {
- removeVpnUserLocked(userHandle);
+ final List<UidRange> removedRanges =
+ uidRangesForUser(userHandle, existingRanges);
+ existingRanges.removeAll(removedRanges);
+ mNetworkCapabilities.setUids(existingRanges);
+ updateCapabilities();
} catch (Exception e) {
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
@@ -1226,15 +1207,6 @@
private void setVpnForcedLocked(boolean enforce) {
final List<String> exemptedPackages =
isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
- setVpnForcedWithExemptionsLocked(enforce, exemptedPackages);
- }
-
- /**
- * @see #setVpnForcedLocked
- */
- @GuardedBy("this")
- private void setVpnForcedWithExemptionsLocked(boolean enforce,
- @Nullable List<String> exemptedPackages) {
final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
Set<UidRange> addedRanges = Collections.emptySet();
@@ -1314,7 +1286,7 @@
synchronized (Vpn.this) {
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
mStatusIntent = null;
- mVpnUsers = null;
+ mNetworkCapabilities.setUids(null);
mConfig = null;
mInterface = null;
if (mConnection != null) {
@@ -1433,12 +1405,7 @@
if (!isRunningLocked()) {
return false;
}
- for (UidRange uidRange : mVpnUsers) {
- if (uidRange.contains(uid)) {
- return true;
- }
- }
- return false;
+ return mNetworkCapabilities.appliesToUid(uid);
}
/**
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index acbc10b..09bce7f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -28,6 +28,8 @@
import android.telephony.TelephonyManager;
import android.net.util.SharedLog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -49,6 +51,7 @@
public class TetheringConfiguration {
private static final String TAG = TetheringConfiguration.class.getSimpleName();
+ @VisibleForTesting
public static final int DUN_NOT_REQUIRED = 0;
public static final int DUN_REQUIRED = 1;
public static final int DUN_UNSPECIFIED = 2;
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 5a3a8be..984c9f8 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -121,6 +121,14 @@
public static final int ICMP_ECHO_DATA_OFFSET = 8;
/**
+ * ICMPv4 constants.
+ *
+ * See also:
+ * - https://tools.ietf.org/html/rfc792
+ */
+ public static final int ICMPV4_ECHO_REQUEST_TYPE = 8;
+
+ /**
* ICMPv6 constants.
*
* See also:
@@ -139,6 +147,8 @@
public static final int ICMPV6_ND_OPTION_TLLA = 2;
public static final int ICMPV6_ND_OPTION_MTU = 5;
+ public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+
/**
* UDP constants.
*
@@ -157,6 +167,14 @@
public static final int DHCP4_CLIENT_PORT = 68;
/**
+ * DNS constants.
+ *
+ * See also:
+ * - https://tools.ietf.org/html/rfc1035
+ */
+ public static final int DNS_SERVER_PORT = 53;
+
+ /**
* Utility functions.
*/
public static byte asByte(int i) { return (byte) i; }
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index e6170cb..4c6a644 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -34,12 +34,15 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import android.os.Parcel;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.ArraySet;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -189,4 +192,84 @@
assertEquals(20, NetworkCapabilities
.maxBandwidth(10, 20));
}
+
+ @Test
+ public void testSetUids() {
+ final NetworkCapabilities netCap = new NetworkCapabilities();
+ final Set<UidRange> uids = new ArraySet<>();
+ uids.add(new UidRange(50, 100));
+ uids.add(new UidRange(3000, 4000));
+ netCap.setUids(uids);
+ assertTrue(netCap.appliesToUid(50));
+ assertTrue(netCap.appliesToUid(80));
+ assertTrue(netCap.appliesToUid(100));
+ assertTrue(netCap.appliesToUid(3000));
+ assertTrue(netCap.appliesToUid(3001));
+ assertFalse(netCap.appliesToUid(10));
+ assertFalse(netCap.appliesToUid(25));
+ assertFalse(netCap.appliesToUid(49));
+ assertFalse(netCap.appliesToUid(101));
+ assertFalse(netCap.appliesToUid(2000));
+ assertFalse(netCap.appliesToUid(100000));
+
+ assertTrue(netCap.appliesToUidRange(new UidRange(50, 100)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(70, 72)));
+ assertTrue(netCap.appliesToUidRange(new UidRange(3500, 3912)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(49, 100)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(1, 10)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 101)));
+ assertFalse(netCap.appliesToUidRange(new UidRange(60, 3400)));
+
+ NetworkCapabilities netCap2 = new NetworkCapabilities();
+ assertFalse(netCap2.satisfiedByUids(netCap));
+ assertFalse(netCap2.equalsUids(netCap));
+ netCap2.setUids(uids);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.equalsUids(netCap2));
+ assertTrue(netCap2.equalsUids(netCap));
+
+ uids.add(new UidRange(600, 700));
+ netCap2.setUids(uids);
+ assertFalse(netCap2.satisfiedByUids(netCap));
+ assertFalse(netCap.appliesToUid(650));
+ assertTrue(netCap2.appliesToUid(650));
+ netCap.combineCapabilities(netCap2);
+ assertTrue(netCap2.satisfiedByUids(netCap));
+ assertTrue(netCap.appliesToUid(650));
+ assertFalse(netCap.appliesToUid(500));
+
+ assertFalse(new NetworkCapabilities().satisfiedByUids(netCap));
+ netCap.combineCapabilities(new NetworkCapabilities());
+ assertTrue(netCap.appliesToUid(500));
+ assertTrue(netCap.appliesToUidRange(new UidRange(1, 100000)));
+ assertFalse(netCap2.appliesToUid(500));
+ assertFalse(netCap2.appliesToUidRange(new UidRange(1, 100000)));
+ assertTrue(new NetworkCapabilities().satisfiedByUids(netCap));
+ }
+
+ @Test
+ public void testParcelNetworkCapabilities() {
+ final Set<UidRange> uids = new ArraySet<>();
+ uids.add(new UidRange(50, 100));
+ uids.add(new UidRange(3000, 4000));
+ final NetworkCapabilities netCap = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .setUids(uids)
+ .addCapability(NET_CAPABILITY_EIMS)
+ .addCapability(NET_CAPABILITY_NOT_METERED);
+ assertEqualsThroughMarshalling(netCap);
+ }
+
+ private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) {
+ Parcel p = Parcel.obtain();
+ netCap.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ byte[] marshalledData = p.marshall();
+
+ p = Parcel.obtain();
+ p.unmarshall(marshalledData, 0, marshalledData.length);
+ p.setDataPosition(0);
+ assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap);
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 70cacb3..6e643a3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -44,6 +44,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
@@ -101,6 +102,7 @@
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.StringNetworkSpecifier;
+import android.net.UidRange;
import android.net.metrics.IpConnectivityLog;
import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
@@ -126,11 +128,13 @@
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.DefaultNetworkMetrics;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -360,7 +364,7 @@
MockNetworkAgent(int transport, LinkProperties linkProperties) {
final int type = transportToLegacyType(transport);
- final String typeName = ConnectivityManager.getNetworkTypeName(type);
+ final String typeName = ConnectivityManager.getNetworkTypeName(transport);
mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(transport);
@@ -377,6 +381,9 @@
case TRANSPORT_WIFI_AWARE:
mScore = 20;
break;
+ case TRANSPORT_VPN:
+ mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
+ break;
default:
throw new UnsupportedOperationException("unimplemented network type");
}
@@ -438,6 +445,11 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
+ public void setUids(Set<UidRange> uids) {
+ mNetworkCapabilities.setUids(uids);
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+
public void setSignalStrength(int signalStrength) {
mNetworkCapabilities.setSignalStrength(signalStrength);
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
@@ -1463,6 +1475,11 @@
return nc;
}
+ void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ assertTrue(fn.test((NetworkCapabilities) cbi.arg));
+ }
+
void assertNoCallback() {
waitForIdle();
CallbackInfo c = mCallbacks.peek();
@@ -3625,4 +3642,76 @@
return;
}
}
+
+ @Test
+ public void testVpnNetworkActive() {
+ final int uid = Process.myUid();
+
+ final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder().build();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_VPN).build();
+ mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+
+ genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnNetworkCallback.assertNoCallback();
+
+ // TODO : check callbacks agree with the return value of mCm.getActiveNetwork().
+ // Right now this is not possible because establish() is not adequately instrumented
+ // in this test.
+
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ vpnNetworkAgent.setUids(ranges);
+ vpnNetworkAgent.connect(false);
+
+ genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ wifiNetworkCallback.assertNoCallback();
+ vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+
+ genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ vpnNetworkCallback.expectCapabilitiesLike(
+ nc -> nc.appliesToUid(uid) && !nc.appliesToUid(uid + 1), vpnNetworkAgent);
+
+ ranges.clear();
+ vpnNetworkAgent.setUids(ranges);
+
+ genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ wifiNetworkCallback.assertNoCallback();
+ vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+
+ ranges.add(new UidRange(uid, uid));
+ vpnNetworkAgent.setUids(ranges);
+
+ genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ wifiNetworkCallback.assertNoCallback();
+ vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+
+ mWiFiNetworkAgent.disconnect();
+
+ genericNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ vpnNetworkCallback.assertNoCallback();
+
+ vpnNetworkAgent.disconnect();
+
+ genericNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ wifiNetworkCallback.assertNoCallback();
+ vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+
+ mCm.unregisterNetworkCallback(genericNetworkCallback);
+ mCm.unregisterNetworkCallback(wifiNetworkCallback);
+ mCm.unregisterNetworkCallback(vpnNetworkCallback);
+ }
}