Merge "NetworkAgent: Send primitive integer in explicitlySelected"
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 40f47b0..104134a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -125,8 +125,8 @@
/**
* A temporary hack until SUPL system can get off the legacy APIS.
* They do too many network requests and the long list of apps listening
- * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive.
- * Use this bcast intent instead for SUPL requests.
+ * and waking due to the CONNECTIVITY_ACTION broadcast makes it expensive.
+ * Use this broadcast intent instead for SUPL requests.
* @hide
*/
public static final String CONNECTIVITY_ACTION_SUPL =
@@ -152,7 +152,7 @@
* call {@link CaptivePortal#reportCaptivePortalDismissed} so the system can
* reevaluate the network. If reevaluation finds the network no longer
* subject to a captive portal, the network may become the default active
- * data network. </li>
+ * data network.</li>
* <li> When the app handling this action believes the user explicitly wants
* to ignore the captive portal and the network, the app should call
* {@link CaptivePortal#ignoreNetwork}. </li>
@@ -238,6 +238,14 @@
public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
/**
+ * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive
+ * portal login activity.
+ * {@hide}
+ */
+ public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
+ "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+
+ /**
* Key for passing a user agent string to the captive portal login activity.
* {@hide}
*/
@@ -252,7 +260,8 @@
* {@hide}
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DATA_ACTIVITY_CHANGE = "android.net.conn.DATA_ACTIVITY_CHANGE";
+ public static final String ACTION_DATA_ACTIVITY_CHANGE =
+ "android.net.conn.DATA_ACTIVITY_CHANGE";
/**
* The lookup key for an enum that indicates the network device type on which this data activity
* change happens.
@@ -383,14 +392,14 @@
/**
* Invalid tethering type.
- * @see #startTethering(int, OnStartTetheringCallback, boolean)
+ * @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
public static final int TETHERING_INVALID = -1;
/**
* Wifi tethering type.
- * @see #startTethering(int, OnStartTetheringCallback, boolean)
+ * @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
@SystemApi
@@ -398,7 +407,7 @@
/**
* USB tethering type.
- * @see #startTethering(int, OnStartTetheringCallback, boolean)
+ * @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
@SystemApi
@@ -406,7 +415,7 @@
/**
* Bluetooth tethering type.
- * @see #startTethering(int, OnStartTetheringCallback, boolean)
+ * @see #startTethering(int, boolean, OnStartTetheringCallback)
* @hide
*/
@SystemApi
@@ -656,7 +665,7 @@
/**
* Static unique request used as a tombstone for NetworkCallbacks that have been unregistered.
* This allows to distinguish when unregistering NetworkCallbacks those that were never
- * registered and those that were already unregistered.
+ * registered from those that were already unregistered.
* @hide
*/
private static final NetworkRequest ALREADY_UNREGISTERED =
@@ -696,7 +705,7 @@
*
* @hide
*/
- public static final String PRIVATE_DNS_DEFAULT_MODE = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+ public static final String PRIVATE_DNS_DEFAULT_MODE_FALLBACK = PRIVATE_DNS_MODE_OPPORTUNISTIC;
private final IConnectivityManager mService;
/**
@@ -1486,8 +1495,8 @@
};
}
- private static HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
- new HashMap<NetworkCapabilities, LegacyRequest>();
+ private static final HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
+ new HashMap<>();
private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) {
synchronized (sLegacyRequests) {
@@ -1627,8 +1636,9 @@
* {@code onStarted} method will be called. If an error occurs, {@code onError} will be called,
* specifying one of the {@code ERROR_*} constants in this class.
*
- * To stop an existing keepalive, call {@link stop}. The system will call {@code onStopped} if
- * the operation was successfull or {@code onError} if an error occurred.
+ * To stop an existing keepalive, call {@link PacketKeepalive#stop}. The system will call
+ * {@link PacketKeepaliveCallback#onStopped} if the operation was successful or
+ * {@link PacketKeepaliveCallback#onError} if an error occurred.
*
* @hide
*/
@@ -1889,7 +1899,7 @@
* to initiate network traffic), you can retrieve its instantaneous state with
* {@link ConnectivityManager#isDefaultNetworkActive}.
*/
- public void onNetworkActive();
+ void onNetworkActive();
}
private INetworkManagementService getNetworkManagementService() {
@@ -1904,8 +1914,7 @@
}
private final ArrayMap<OnNetworkActiveListener, INetworkActivityListener>
- mNetworkActivityListeners
- = new ArrayMap<OnNetworkActiveListener, INetworkActivityListener>();
+ mNetworkActivityListeners = new ArrayMap<>();
/**
* Start listening to reports when the system's default data network is active, meaning it is
@@ -2208,12 +2217,12 @@
/**
* Called when tethering has been successfully started.
*/
- public void onTetheringStarted() {};
+ public void onTetheringStarted() {}
/**
* Called when starting tethering failed.
*/
- public void onTetheringFailed() {};
+ public void onTetheringFailed() {}
}
/**
@@ -2650,9 +2659,6 @@
/**
* Set sign in error notification to visible or in visible
*
- * @param visible
- * @param networkType
- *
* {@hide}
* @deprecated Doesn't properly deal with multiple connected networks of the same type.
*/
@@ -2861,7 +2867,7 @@
* @hide
*/
public interface Errors {
- static int TOO_MANY_REQUESTS = 1;
+ int TOO_MANY_REQUESTS = 1;
}
/** @hide */
@@ -3118,7 +3124,7 @@
* as these {@code NetworkCapabilities} represent states that a particular
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfing a request with these capabilities.
+ * know how to go about satisfying a request with these capabilities.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3178,7 +3184,7 @@
* Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
* by a timeout.
*
- * This function behaves identically to the non-timedout version, but if a suitable
+ * This function behaves identically to the version without timeout, but if a suitable
* network is not found within the given time (in milliseconds) the
* {@link NetworkCallback#onUnavailable} callback is called. The request can still be
* released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)} but does
@@ -3259,7 +3265,7 @@
* as these {@code NetworkCapabilities} represent states that a particular
* network may never attain, and whether a network will attain these states
* is unknown prior to bringing up the network so the framework does not
- * know how to go about satisfing a request with these capabilities.
+ * know how to go about satisfying a request with these capabilities.
*
* <p>This method requires the caller to hold either the
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
@@ -3424,9 +3430,9 @@
// capabilities, this request is guaranteed, at all times, to be
// satisfied by the same network, if any, that satisfies the default
// request, i.e., the system default network.
- NetworkCapabilities nullCapabilities = null;
CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(nullCapabilities, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
+ sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+ REQUEST, TYPE_NONE, cbHandler);
}
/**
@@ -3661,7 +3667,7 @@
* @return {@code true} on success, {@code false} if the {@link Network} is no longer valid.
*/
public boolean bindProcessToNetwork(Network network) {
- // Forcing callers to call thru non-static function ensures ConnectivityManager
+ // Forcing callers to call through non-static function ensures ConnectivityManager
// instantiated.
return setProcessDefaultNetwork(network);
}
@@ -3856,4 +3862,20 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * The network watchlist is a list of domains and IP addresses that are associated with
+ * potentially harmful apps. This method returns the SHA-256 of the watchlist config file
+ * currently used by the system for validation purposes.
+ *
+ * @return Hash of network watchlist config file. Null if config does not exist.
+ */
+ public byte[] getNetworkWatchlistConfigHash() {
+ try {
+ return mService.getNetworkWatchlistConfigHash();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to get watchlist config hash");
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index a6fe738..ce95b60 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -180,4 +180,6 @@
void stopKeepalive(in Network network, int slot);
String getCaptivePortalServerUrl();
+
+ byte[] getNetworkWatchlistConfigHash();
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index f525b1f..bd2db92 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -32,6 +32,7 @@
import java.util.Hashtable;
import java.util.List;
import java.util.Objects;
+import java.util.StringJoiner;
/**
* Describes the properties of a network link.
@@ -48,12 +49,13 @@
public final class LinkProperties implements Parcelable {
// The interface described by the network link.
private String mIfaceName;
- private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
- private ArrayList<InetAddress> mDnses = new ArrayList<InetAddress>();
+ private ArrayList<LinkAddress> mLinkAddresses = new ArrayList<>();
+ private ArrayList<InetAddress> mDnses = new ArrayList<>();
+ private ArrayList<InetAddress> mValidatedPrivateDnses = new ArrayList<>();
private boolean mUsePrivateDns;
private String mPrivateDnsServerName;
private String mDomains;
- private ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+ private ArrayList<RouteInfo> mRoutes = new ArrayList<>();
private ProxyInfo mHttpProxy;
private int mMtu;
// in the format "rmem_min,rmem_def,rmem_max,wmem_min,wmem_def,wmem_max"
@@ -65,15 +67,14 @@
// Stores the properties of links that are "stacked" above this link.
// Indexed by interface name to allow modification and to prevent duplicates being added.
- private Hashtable<String, LinkProperties> mStackedLinks =
- new Hashtable<String, LinkProperties>();
+ private Hashtable<String, LinkProperties> mStackedLinks = new Hashtable<>();
/**
* @hide
*/
public static class CompareResult<T> {
- public final List<T> removed = new ArrayList<T>();
- public final List<T> added = new ArrayList<T>();
+ public final List<T> removed = new ArrayList<>();
+ public final List<T> added = new ArrayList<>();
public CompareResult() {}
@@ -92,12 +93,9 @@
@Override
public String toString() {
- String retVal = "removed=[";
- for (T addr : removed) retVal += addr.toString() + ",";
- retVal += "] added=[";
- for (T addr : added) retVal += addr.toString() + ",";
- retVal += "]";
- return retVal;
+ return "removed=[" + TextUtils.join(",", removed)
+ + "] added=[" + TextUtils.join(",", added)
+ + "]";
}
}
@@ -119,7 +117,7 @@
public static ProvisioningChange compareProvisioning(
LinkProperties before, LinkProperties after) {
if (before.isProvisioned() && after.isProvisioned()) {
- // On dualstack networks, DHCPv4 renewals can occasionally fail.
+ // On dual-stack networks, DHCPv4 renewals can occasionally fail.
// When this happens, IPv6-reachable services continue to function
// normally but IPv4-only services (naturally) fail.
//
@@ -130,7 +128,7 @@
//
// For users, this is confusing and unexpected behaviour, and is
// not necessarily easy to diagnose. Therefore, we treat changing
- // from a dualstack network to an IPv6-only network equivalent to
+ // from a dual-stack network to an IPv6-only network equivalent to
// a total loss of provisioning.
//
// For one such example of this, see b/18867306.
@@ -138,7 +136,7 @@
// Additionally, losing IPv6 provisioning can result in TCP
// connections getting stuck until timeouts fire and other
// baffling failures. Therefore, loss of either IPv4 or IPv6 on a
- // previously dualstack network is deemed a lost of provisioning.
+ // previously dual-stack network is deemed a lost of provisioning.
if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) ||
(before.isIPv6Provisioned() && !after.isIPv6Provisioned())) {
return ProvisioningChange.LOST_PROVISIONING;
@@ -164,19 +162,19 @@
*/
public LinkProperties(LinkProperties source) {
if (source != null) {
- mIfaceName = source.getInterfaceName();
- for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l);
- for (InetAddress i : source.getDnsServers()) mDnses.add(i);
+ mIfaceName = source.mIfaceName;
+ mLinkAddresses.addAll(source.mLinkAddresses);
+ mDnses.addAll(source.mDnses);
+ mValidatedPrivateDnses.addAll(source.mValidatedPrivateDnses);
mUsePrivateDns = source.mUsePrivateDns;
mPrivateDnsServerName = source.mPrivateDnsServerName;
- mDomains = source.getDomains();
- for (RouteInfo r : source.getRoutes()) mRoutes.add(r);
- mHttpProxy = (source.getHttpProxy() == null) ?
- null : new ProxyInfo(source.getHttpProxy());
+ mDomains = source.mDomains;
+ mRoutes.addAll(source.mRoutes);
+ mHttpProxy = (source.mHttpProxy == null) ? null : new ProxyInfo(source.mHttpProxy);
for (LinkProperties l: source.mStackedLinks.values()) {
addStackedLink(l);
}
- setMtu(source.getMtu());
+ setMtu(source.mMtu);
mTcpBufferSizes = source.mTcpBufferSizes;
}
}
@@ -190,7 +188,7 @@
*/
public void setInterfaceName(String iface) {
mIfaceName = iface;
- ArrayList<RouteInfo> newRoutes = new ArrayList<RouteInfo>(mRoutes.size());
+ ArrayList<RouteInfo> newRoutes = new ArrayList<>(mRoutes.size());
for (RouteInfo route : mRoutes) {
newRoutes.add(routeWithInterface(route));
}
@@ -210,8 +208,8 @@
* @hide
*/
public List<String> getAllInterfaceNames() {
- List<String> interfaceNames = new ArrayList<String>(mStackedLinks.size() + 1);
- if (mIfaceName != null) interfaceNames.add(new String(mIfaceName));
+ List<String> interfaceNames = new ArrayList<>(mStackedLinks.size() + 1);
+ if (mIfaceName != null) interfaceNames.add(mIfaceName);
for (LinkProperties stacked: mStackedLinks.values()) {
interfaceNames.addAll(stacked.getAllInterfaceNames());
}
@@ -225,11 +223,11 @@
* prefix lengths for each address. This is a simplified utility alternative to
* {@link LinkProperties#getLinkAddresses}.
*
- * @return An umodifiable {@link List} of {@link InetAddress} for this link.
+ * @return An unmodifiable {@link List} of {@link InetAddress} for this link.
* @hide
*/
public List<InetAddress> getAddresses() {
- List<InetAddress> addresses = new ArrayList<InetAddress>();
+ List<InetAddress> addresses = new ArrayList<>();
for (LinkAddress linkAddress : mLinkAddresses) {
addresses.add(linkAddress.getAddress());
}
@@ -241,7 +239,7 @@
* @hide
*/
public List<InetAddress> getAllAddresses() {
- List<InetAddress> addresses = new ArrayList<InetAddress>();
+ List<InetAddress> addresses = new ArrayList<>();
for (LinkAddress linkAddress : mLinkAddresses) {
addresses.add(linkAddress.getAddress());
}
@@ -318,8 +316,7 @@
* @hide
*/
public List<LinkAddress> getAllLinkAddresses() {
- List<LinkAddress> addresses = new ArrayList<LinkAddress>();
- addresses.addAll(mLinkAddresses);
+ List<LinkAddress> addresses = new ArrayList<>(mLinkAddresses);
for (LinkProperties stacked: mStackedLinks.values()) {
addresses.addAll(stacked.getAllLinkAddresses());
}
@@ -374,7 +371,7 @@
* Replaces the DNS servers in this {@code LinkProperties} with
* the given {@link Collection} of {@link InetAddress} objects.
*
- * @param addresses The {@link Collection} of DNS servers to set in this object.
+ * @param dnsServers The {@link Collection} of DNS servers to set in this object.
* @hide
*/
public void setDnsServers(Collection<InetAddress> dnsServers) {
@@ -387,7 +384,7 @@
/**
* Returns all the {@link InetAddress} for DNS servers on this link.
*
- * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on
+ * @return An unmodifiable {@link List} of {@link InetAddress} for DNS servers on
* this link.
*/
public List<InetAddress> getDnsServers() {
@@ -448,6 +445,65 @@
}
/**
+ * Adds the given {@link InetAddress} to the list of validated private DNS servers,
+ * if not present. This is distinct from the server name in that these are actually
+ * resolved addresses.
+ *
+ * @param dnsServer The {@link InetAddress} to add to the list of validated private DNS servers.
+ * @return true if the DNS server was added, false if it was already present.
+ * @hide
+ */
+ public boolean addValidatedPrivateDnsServer(InetAddress dnsServer) {
+ if (dnsServer != null && !mValidatedPrivateDnses.contains(dnsServer)) {
+ mValidatedPrivateDnses.add(dnsServer);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Removes the given {@link InetAddress} from the list of validated private DNS servers.
+ *
+ * @param dnsServer The {@link InetAddress} to remove from the list of validated private DNS
+ * servers.
+ * @return true if the DNS server was removed, false if it did not exist.
+ * @hide
+ */
+ public boolean removeValidatedPrivateDnsServer(InetAddress dnsServer) {
+ if (dnsServer != null) {
+ return mValidatedPrivateDnses.remove(dnsServer);
+ }
+ return false;
+ }
+
+ /**
+ * Replaces the validated private DNS servers in this {@code LinkProperties} with
+ * the given {@link Collection} of {@link InetAddress} objects.
+ *
+ * @param dnsServers The {@link Collection} of validated private DNS servers to set in this
+ * object.
+ * @hide
+ */
+ public void setValidatedPrivateDnsServers(Collection<InetAddress> dnsServers) {
+ mValidatedPrivateDnses.clear();
+ for (InetAddress dnsServer: dnsServers) {
+ addValidatedPrivateDnsServer(dnsServer);
+ }
+ }
+
+ /**
+ * Returns all the {@link InetAddress} for validated private DNS servers on this link.
+ * These are resolved from the private DNS server name.
+ *
+ * @return An umodifiable {@link List} of {@link InetAddress} for validated private
+ * DNS servers on this link.
+ * @hide
+ */
+ public List<InetAddress> getValidatedPrivateDnsServers() {
+ return Collections.unmodifiableList(mValidatedPrivateDnses);
+ }
+
+ /**
* Sets the DNS domain search path used on this link.
*
* @param domains A {@link String} listing in priority order the comma separated
@@ -580,7 +636,7 @@
* @hide
*/
public void ensureDirectlyConnectedRoutes() {
- for (LinkAddress addr: mLinkAddresses) {
+ for (LinkAddress addr : mLinkAddresses) {
addRoute(new RouteInfo(addr, null, mIfaceName));
}
}
@@ -590,8 +646,7 @@
* @hide
*/
public List<RouteInfo> getAllRoutes() {
- List<RouteInfo> routes = new ArrayList<>();
- routes.addAll(mRoutes);
+ List<RouteInfo> routes = new ArrayList<>(mRoutes);
for (LinkProperties stacked: mStackedLinks.values()) {
routes.addAll(stacked.getAllRoutes());
}
@@ -622,7 +677,7 @@
/**
* Adds a stacked link.
*
- * If there is already a stacked link with the same interfacename as link,
+ * If there is already a stacked link with the same interface name as link,
* that link is replaced with link. Otherwise, link is added to the list
* of stacked links. If link is null, nothing changes.
*
@@ -662,9 +717,9 @@
*/
public @NonNull List<LinkProperties> getStackedLinks() {
if (mStackedLinks.isEmpty()) {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
- List<LinkProperties> stacked = new ArrayList<LinkProperties>();
+ List<LinkProperties> stacked = new ArrayList<>();
for (LinkProperties link : mStackedLinks.values()) {
stacked.add(new LinkProperties(link));
}
@@ -698,48 +753,76 @@
@Override
public String toString() {
- String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " ");
+ // Space as a separator, so no need for spaces at start/end of the individual fragments.
+ final StringJoiner resultJoiner = new StringJoiner(" ", "{", "}");
- String linkAddresses = "LinkAddresses: [";
- for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ",";
- linkAddresses += "] ";
-
- String dns = "DnsAddresses: [";
- for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ",";
- dns += "] ";
-
- String usePrivateDns = "UsePrivateDns: " + mUsePrivateDns + " ";
-
- String privateDnsServerName = "";
- if (privateDnsServerName != null) {
- privateDnsServerName = "PrivateDnsServerName: " + mPrivateDnsServerName + " ";
+ if (mIfaceName != null) {
+ resultJoiner.add("InterfaceName:");
+ resultJoiner.add(mIfaceName);
}
- String domainName = "Domains: " + mDomains;
+ resultJoiner.add("LinkAddresses: [");
+ if (!mLinkAddresses.isEmpty()) {
+ resultJoiner.add(TextUtils.join(",", mLinkAddresses));
+ }
+ resultJoiner.add("]");
- String mtu = " MTU: " + mMtu;
+ resultJoiner.add("DnsAddresses: [");
+ if (!mDnses.isEmpty()) {
+ resultJoiner.add(TextUtils.join(",", mDnses));
+ }
+ resultJoiner.add("]");
- String tcpBuffSizes = "";
- if (mTcpBufferSizes != null) {
- tcpBuffSizes = " TcpBufferSizes: " + mTcpBufferSizes;
+ if (mUsePrivateDns) {
+ resultJoiner.add("UsePrivateDns: true");
}
- String routes = " Routes: [";
- for (RouteInfo route : mRoutes) routes += route.toString() + ",";
- routes += "] ";
- String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " ");
+ if (mPrivateDnsServerName != null) {
+ resultJoiner.add("PrivateDnsServerName:");
+ resultJoiner.add(mPrivateDnsServerName);
+ }
- String stacked = "";
- if (mStackedLinks.values().size() > 0) {
- stacked += " Stacked: [";
- for (LinkProperties link: mStackedLinks.values()) {
- stacked += " [" + link.toString() + " ],";
+ if (!mValidatedPrivateDnses.isEmpty()) {
+ final StringJoiner validatedPrivateDnsesJoiner =
+ new StringJoiner(",", "ValidatedPrivateDnsAddresses: [", "]");
+ for (final InetAddress addr : mValidatedPrivateDnses) {
+ validatedPrivateDnsesJoiner.add(addr.getHostAddress());
}
- stacked += "] ";
+ resultJoiner.add(validatedPrivateDnsesJoiner.toString());
}
- return "{" + ifaceName + linkAddresses + routes + dns + usePrivateDns
- + privateDnsServerName + domainName + mtu + tcpBuffSizes + proxy
- + stacked + "}";
+
+ resultJoiner.add("Domains:");
+ resultJoiner.add(mDomains);
+
+ resultJoiner.add("MTU:");
+ resultJoiner.add(Integer.toString(mMtu));
+
+ if (mTcpBufferSizes != null) {
+ resultJoiner.add("TcpBufferSizes:");
+ resultJoiner.add(mTcpBufferSizes);
+ }
+
+ resultJoiner.add("Routes: [");
+ if (!mRoutes.isEmpty()) {
+ resultJoiner.add(TextUtils.join(",", mRoutes));
+ }
+ resultJoiner.add("]");
+
+ if (mHttpProxy != null) {
+ resultJoiner.add("HttpProxy:");
+ resultJoiner.add(mHttpProxy.toString());
+ }
+
+ final Collection<LinkProperties> stackedLinksValues = mStackedLinks.values();
+ if (!stackedLinksValues.isEmpty()) {
+ final StringJoiner stackedLinksJoiner = new StringJoiner(",", "Stacked: [", "]");
+ for (final LinkProperties lp : stackedLinksValues) {
+ stackedLinksJoiner.add("[ " + lp + " ]");
+ }
+ resultJoiner.add(stackedLinksJoiner.toString());
+ }
+
+ return resultJoiner.toString();
}
/**
@@ -956,10 +1039,10 @@
if (mDomains == null) {
if (targetDomains != null) return false;
} else {
- if (mDomains.equals(targetDomains) == false) return false;
+ if (!mDomains.equals(targetDomains)) return false;
}
return (mDnses.size() == targetDnses.size()) ?
- mDnses.containsAll(targetDnses) : false;
+ mDnses.containsAll(targetDnses) : false;
}
/**
@@ -977,6 +1060,20 @@
}
/**
+ * Compares this {@code LinkProperties} validated private DNS addresses against
+ * the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isIdenticalValidatedPrivateDnses(LinkProperties target) {
+ Collection<InetAddress> targetDnses = target.getValidatedPrivateDnsServers();
+ return (mValidatedPrivateDnses.size() == targetDnses.size())
+ ? mValidatedPrivateDnses.containsAll(targetDnses) : false;
+ }
+
+ /**
* Compares this {@code LinkProperties} Routes against the target
*
* @param target LinkProperties to compare.
@@ -986,7 +1083,7 @@
public boolean isIdenticalRoutes(LinkProperties target) {
Collection<RouteInfo> targetRoutes = target.getRoutes();
return (mRoutes.size() == targetRoutes.size()) ?
- mRoutes.containsAll(targetRoutes) : false;
+ mRoutes.containsAll(targetRoutes) : false;
}
/**
@@ -998,7 +1095,7 @@
*/
public boolean isIdenticalHttpProxy(LinkProperties target) {
return getHttpProxy() == null ? target.getHttpProxy() == null :
- getHttpProxy().equals(target.getHttpProxy());
+ getHttpProxy().equals(target.getHttpProxy());
}
/**
@@ -1044,7 +1141,6 @@
return Objects.equals(mTcpBufferSizes, target.mTcpBufferSizes);
}
- @Override
/**
* Compares this {@code LinkProperties} instance against the target
* LinkProperties in {@code obj}. Two LinkPropertieses are equal if
@@ -1059,13 +1155,14 @@
* @param obj the object to be tested for equality.
* @return {@code true} if both objects are equal, {@code false} otherwise.
*/
+ @Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof LinkProperties)) return false;
LinkProperties target = (LinkProperties) obj;
- /**
+ /*
* This method does not check that stacked interfaces are equal, because
* stacked interfaces are not so much a property of the link as a
* description of connections between links.
@@ -1074,6 +1171,7 @@
&& isIdenticalAddresses(target)
&& isIdenticalDnses(target)
&& isIdenticalPrivateDns(target)
+ && isIdenticalValidatedPrivateDnses(target)
&& isIdenticalRoutes(target)
&& isIdenticalHttpProxy(target)
&& isIdenticalStackedLinks(target)
@@ -1121,6 +1219,19 @@
}
/**
+ * Compares the validated private DNS addresses in this LinkProperties with another
+ * LinkProperties.
+ *
+ * @param target a LinkProperties with the new list of validated private dns addresses
+ * @return the differences between the DNS addresses.
+ * @hide
+ */
+ public CompareResult<InetAddress> compareValidatedPrivateDnses(LinkProperties target) {
+ return new CompareResult<>(mValidatedPrivateDnses,
+ target != null ? target.getValidatedPrivateDnsServers() : null);
+ }
+
+ /**
* Compares all routes in this LinkProperties with another LinkProperties,
* examining both the the base link and all stacked links.
*
@@ -1158,16 +1269,18 @@
}
- @Override
/**
- * generate hashcode based on significant fields
+ * Generate hashcode based on significant fields
+ *
* Equal objects must produce the same hash code, while unequal objects
* may have the same hash codes.
*/
+ @Override
public int hashCode() {
return ((null == mIfaceName) ? 0 : mIfaceName.hashCode()
+ mLinkAddresses.size() * 31
+ mDnses.size() * 37
+ + mValidatedPrivateDnses.size() * 61
+ ((null == mDomains) ? 0 : mDomains.hashCode())
+ mRoutes.size() * 41
+ ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())
@@ -1184,12 +1297,16 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(getInterfaceName());
dest.writeInt(mLinkAddresses.size());
- for(LinkAddress linkAddress : mLinkAddresses) {
+ for (LinkAddress linkAddress : mLinkAddresses) {
dest.writeParcelable(linkAddress, flags);
}
dest.writeInt(mDnses.size());
- for(InetAddress d : mDnses) {
+ for (InetAddress d : mDnses) {
+ dest.writeByteArray(d.getAddress());
+ }
+ dest.writeInt(mValidatedPrivateDnses.size());
+ for (InetAddress d : mValidatedPrivateDnses) {
dest.writeByteArray(d.getAddress());
}
dest.writeBoolean(mUsePrivateDns);
@@ -1198,7 +1315,7 @@
dest.writeInt(mMtu);
dest.writeString(mTcpBufferSizes);
dest.writeInt(mRoutes.size());
- for(RouteInfo route : mRoutes) {
+ for (RouteInfo route : mRoutes) {
dest.writeParcelable(route, flags);
}
@@ -1208,7 +1325,7 @@
} else {
dest.writeByte((byte)0);
}
- ArrayList<LinkProperties> stackedLinks = new ArrayList(mStackedLinks.values());
+ ArrayList<LinkProperties> stackedLinks = new ArrayList<>(mStackedLinks.values());
dest.writeList(stackedLinks);
}
@@ -1225,26 +1342,33 @@
netProp.setInterfaceName(iface);
}
int addressCount = in.readInt();
- for (int i=0; i<addressCount; i++) {
- netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
+ for (int i = 0; i < addressCount; i++) {
+ netProp.addLinkAddress(in.readParcelable(null));
}
addressCount = in.readInt();
- for (int i=0; i<addressCount; i++) {
+ for (int i = 0; i < addressCount; i++) {
try {
netProp.addDnsServer(InetAddress.getByAddress(in.createByteArray()));
} catch (UnknownHostException e) { }
}
+ addressCount = in.readInt();
+ for (int i = 0; i < addressCount; i++) {
+ try {
+ netProp.addValidatedPrivateDnsServer(
+ InetAddress.getByAddress(in.createByteArray()));
+ } catch (UnknownHostException e) { }
+ }
netProp.setUsePrivateDns(in.readBoolean());
netProp.setPrivateDnsServerName(in.readString());
netProp.setDomains(in.readString());
netProp.setMtu(in.readInt());
netProp.setTcpBufferSizes(in.readString());
addressCount = in.readInt();
- for (int i=0; i<addressCount; i++) {
- netProp.addRoute((RouteInfo)in.readParcelable(null));
+ for (int i = 0; i < addressCount; i++) {
+ netProp.addRoute(in.readParcelable(null));
}
if (in.readByte() == 1) {
- netProp.setHttpProxy((ProxyInfo)in.readParcelable(null));
+ netProp.setHttpProxy(in.readParcelable(null));
}
ArrayList<LinkProperties> stackedLinks = new ArrayList<LinkProperties>();
in.readList(stackedLinks, LinkProperties.class.getClassLoader());
@@ -1259,16 +1383,15 @@
}
};
- /**
- * Check the valid MTU range based on IPv4 or IPv6.
- * @hide
- */
- public static boolean isValidMtu(int mtu, boolean ipv6) {
- if (ipv6) {
- if ((mtu >= MIN_MTU_V6 && mtu <= MAX_MTU)) return true;
- } else {
- if ((mtu >= MIN_MTU && mtu <= MAX_MTU)) return true;
- }
- return false;
+ /**
+ * Check the valid MTU range based on IPv4 or IPv6.
+ * @hide
+ */
+ public static boolean isValidMtu(int mtu, boolean ipv6) {
+ if (ipv6) {
+ return mtu >= MIN_MTU_V6 && mtu <= MAX_MTU;
+ } else {
+ return mtu >= MIN_MTU && mtu <= MAX_MTU;
}
+ }
}
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index f14847f..512e35e 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -21,6 +21,7 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
+import android.util.proto.ProtoOutputStream;
import com.android.okhttp.internalandroidapi.Dns;
import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
@@ -78,6 +79,26 @@
httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
private static final long httpKeepAliveDurationMs =
Long.parseLong(System.getProperty("http.keepAliveDuration", "300000")); // 5 minutes.
+ // Value used to obfuscate network handle longs.
+ // The HANDLE_MAGIC value MUST be kept in sync with the corresponding
+ // value in the native/android/net.c NDK implementation.
+ private static final long HANDLE_MAGIC = 0xcafed00dL;
+ private static final int HANDLE_MAGIC_SIZE = 32;
+
+ // A boolean to control how getAllByName()/getByName() behaves in the face
+ // of Private DNS.
+ //
+ // When true, these calls will request that DNS resolution bypass any
+ // Private DNS that might otherwise apply. Use of this feature is restricted
+ // and permission checks are made by netd (attempts to bypass Private DNS
+ // without appropriate permission are silently turned into vanilla DNS
+ // requests). This only affects DNS queries made using this network object.
+ //
+ // It it not parceled to receivers because (a) it can be set or cleared at
+ // anytime and (b) receivers should be explicit about attempts to bypass
+ // Private DNS so that the intent of the code is easily determined and
+ // code search audits are possible.
+ private boolean mPrivateDnsBypass = false;
/**
* @hide
@@ -102,7 +123,7 @@
* @throws UnknownHostException if the address lookup fails.
*/
public InetAddress[] getAllByName(String host) throws UnknownHostException {
- return InetAddress.getAllByNameOnNet(host, netId);
+ return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
}
/**
@@ -116,20 +137,38 @@
* if the address lookup fails.
*/
public InetAddress getByName(String host) throws UnknownHostException {
- return InetAddress.getByNameOnNet(host, netId);
+ return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+ }
+
+ /**
+ * Specify whether or not Private DNS should be bypassed when attempting
+ * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given
+ * instance for hostname resolution.
+ *
+ * @hide
+ */
+ public void setPrivateDnsBypass(boolean bypass) {
+ mPrivateDnsBypass = bypass;
+ }
+
+ /**
+ * Returns a netid marked with the Private DNS bypass flag.
+ *
+ * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
+ * in system/netd/include/NetdClient.h.
+ *
+ * @hide
+ */
+ public int getNetIdForResolv() {
+ return mPrivateDnsBypass
+ ? (int) (0x80000000L | (long) netId) // Non-portable DNS resolution flag.
+ : netId;
}
/**
* A {@code SocketFactory} that produces {@code Socket}'s bound to this network.
*/
private class NetworkBoundSocketFactory extends SocketFactory {
- private final int mNetId;
-
- public NetworkBoundSocketFactory(int netId) {
- super();
- mNetId = netId;
- }
-
private Socket connectToHost(String host, int port, SocketAddress localAddress)
throws IOException {
// Lookup addresses only on this Network.
@@ -155,7 +194,8 @@
}
@Override
- public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
+ public Socket createSocket(String host, int port, InetAddress localHost, int localPort)
+ throws IOException {
return connectToHost(host, port, new InetSocketAddress(localHost, localPort));
}
@@ -219,7 +259,7 @@
if (mNetworkBoundSocketFactory == null) {
synchronized (mLock) {
if (mNetworkBoundSocketFactory == null) {
- mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId);
+ mNetworkBoundSocketFactory = new NetworkBoundSocketFactory();
}
}
}
@@ -360,6 +400,25 @@
}
/**
+ * Returns a {@link Network} object given a handle returned from {@link #getNetworkHandle}.
+ *
+ * @param networkHandle a handle returned from {@link #getNetworkHandle}.
+ * @return A {@link Network} object derived from {@code networkHandle}.
+ */
+ public static Network fromNetworkHandle(long networkHandle) {
+ if (networkHandle == 0) {
+ throw new IllegalArgumentException(
+ "Network.fromNetworkHandle refusing to instantiate NETID_UNSET Network.");
+ }
+ if ((networkHandle & ((1L << HANDLE_MAGIC_SIZE) - 1)) != HANDLE_MAGIC
+ || networkHandle < 0) {
+ throw new IllegalArgumentException(
+ "Value passed to fromNetworkHandle() is not a network handle.");
+ }
+ return new Network((int) (networkHandle >> HANDLE_MAGIC_SIZE));
+ }
+
+ /**
* Returns a handle representing this {@code Network}, for use with the NDK API.
*/
public long getNetworkHandle() {
@@ -381,14 +440,10 @@
// At some future date it may be desirable to realign the handle with
// Multiple Provisioning Domains API recommendations, as made by the
// IETF mif working group.
- //
- // The handleMagic value MUST be kept in sync with the corresponding
- // value in the native/android/net.c NDK implementation.
if (netId == 0) {
return 0L; // make this zero condition obvious for debugging
}
- final long handleMagic = 0xcafed00dL;
- return (((long) netId) << 32) | handleMagic;
+ return (((long) netId) << HANDLE_MAGIC_SIZE) | HANDLE_MAGIC;
}
// implement the Parcelable interface
@@ -414,7 +469,7 @@
@Override
public boolean equals(Object obj) {
- if (obj instanceof Network == false) return false;
+ if (!(obj instanceof Network)) return false;
Network other = (Network)obj;
return this.netId == other.netId;
}
@@ -428,4 +483,11 @@
public String toString() {
return Integer.toString(netId);
}
+
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(NetworkProto.NET_ID, netId);
+ proto.end(token);
+ }
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 19f0c90..72b4bfd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,10 +17,13 @@
package android.net;
import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
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;
@@ -60,15 +63,7 @@
public NetworkCapabilities(NetworkCapabilities nc) {
if (nc != null) {
- mNetworkCapabilities = nc.mNetworkCapabilities;
- mTransportTypes = nc.mTransportTypes;
- mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
- mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
- mNetworkSpecifier = nc.mNetworkSpecifier;
- mSignalStrength = nc.mSignalStrength;
- mUids = nc.mUids;
- mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
- mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
+ set(nc);
}
}
@@ -84,6 +79,24 @@
mSignalStrength = SIGNAL_STRENGTH_UNSPECIFIED;
mUids = null;
mEstablishingVpnAppUid = INVALID_UID;
+ mSSID = null;
+ }
+
+ /**
+ * Set all contents of this object to the contents of a NetworkCapabilities.
+ * @hide
+ */
+ public void set(NetworkCapabilities nc) {
+ mNetworkCapabilities = nc.mNetworkCapabilities;
+ mTransportTypes = nc.mTransportTypes;
+ mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps;
+ mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps;
+ mNetworkSpecifier = nc.mNetworkSpecifier;
+ mSignalStrength = nc.mSignalStrength;
+ setUids(nc.mUids); // Will make the defensive copy
+ mEstablishingVpnAppUid = nc.mEstablishingVpnAppUid;
+ mUnwantedNetworkCapabilities = nc.mUnwantedNetworkCapabilities;
+ mSSID = nc.mSSID;
}
/**
@@ -252,9 +265,8 @@
/**
* Indicates that this network is not congested.
* <p>
- * When a network is congested, the device should defer network traffic that
- * can be done at a later time without breaking developer contracts.
- * @hide
+ * When a network is congested, applications should defer network traffic
+ * that can be done at a later time, such as uploading analytics.
*/
public static final int NET_CAPABILITY_NOT_CONGESTED = 20;
@@ -275,6 +287,7 @@
* this network can be used by system apps to upload telemetry data.
* @hide
*/
+ @SystemApi
public static final int NET_CAPABILITY_OEM_PAID = 22;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
@@ -423,6 +436,7 @@
* @return an array of capability values for this instance.
* @hide
*/
+ @TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
@@ -687,6 +701,7 @@
* @return an array of transport type values for this instance.
* @hide
*/
+ @TestApi
public @Transport int[] getTransportTypes() {
return BitUtils.unpackBits(mTransportTypes);
}
@@ -920,7 +935,7 @@
/**
* Sets the signal strength. This is a signed integer, with higher values indicating a stronger
* signal. The exact units are bearer-dependent. For example, Wi-Fi uses the same RSSI units
- * reported by WifiManager.
+ * reported by wifi code.
* <p>
* Note that when used to register a network callback, this specifies the minimum acceptable
* signal strength. When received as the state of an existing network it specifies the current
@@ -1052,7 +1067,7 @@
}
/**
- * Tests if the set of UIDs that this network applies to is the same of the passed set of UIDs.
+ * Tests if the set of UIDs that this network applies to is the same as the passed network.
* <p>
* This test only checks whether equal range objects are in both sets. It will
* return false if the ranges are not exactly the same, even if the covered UIDs
@@ -1142,6 +1157,62 @@
mUids.addAll(nc.mUids);
}
+
+ /**
+ * The SSID of the network, or null if not applicable or unknown.
+ * <p>
+ * This is filled in by wifi code.
+ * @hide
+ */
+ private String mSSID;
+
+ /**
+ * Sets the SSID of this network.
+ * @hide
+ */
+ public NetworkCapabilities setSSID(String ssid) {
+ mSSID = ssid;
+ return this;
+ }
+
+ /**
+ * Gets the SSID of this network, or null if none or unknown.
+ * @hide
+ */
+ public String getSSID() {
+ return mSSID;
+ }
+
+ /**
+ * Tests if the SSID of this network is the same as the SSID of the passed network.
+ * @hide
+ */
+ public boolean equalsSSID(NetworkCapabilities nc) {
+ return Objects.equals(mSSID, nc.mSSID);
+ }
+
+ /**
+ * Check if the SSID requirements of this object are matched by the passed object.
+ * @hide
+ */
+ public boolean satisfiedBySSID(NetworkCapabilities nc) {
+ return mSSID == null || mSSID.equals(nc.mSSID);
+ }
+
+ /**
+ * Combine SSIDs of the capabilities.
+ * <p>
+ * This is only legal if either the SSID of this object is null, or both SSIDs are
+ * equal.
+ * @hide
+ */
+ private void combineSSIDs(NetworkCapabilities nc) {
+ if (mSSID != null && !mSSID.equals(nc.mSSID)) {
+ throw new IllegalStateException("Can't combine two SSIDs");
+ }
+ setSSID(nc.mSSID);
+ }
+
/**
* Combine a set of Capabilities to this one. Useful for coming up with the complete set.
* <p>
@@ -1157,6 +1228,7 @@
combineSpecifiers(nc);
combineSignalStrength(nc);
combineUids(nc);
+ combineSSIDs(nc);
}
/**
@@ -1175,7 +1247,8 @@
&& (onlyImmutable || satisfiedByLinkBandwidths(nc))
&& satisfiedBySpecifier(nc)
&& (onlyImmutable || satisfiedBySignalStrength(nc))
- && (onlyImmutable || satisfiedByUids(nc)));
+ && (onlyImmutable || satisfiedByUids(nc))
+ && (onlyImmutable || satisfiedBySSID(nc)));
}
/**
@@ -1216,9 +1289,7 @@
// Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
// TODO: properly support NOT_METERED as a mutable and requestable capability.
- // Ignore DUN being added or removed. http://b/65257223.
- final long mask = ~MUTABLE_CAPABILITIES
- & ~(1 << NET_CAPABILITY_NOT_METERED) & ~(1 << NET_CAPABILITY_DUN);
+ final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
long oldImmutableCapabilities = this.mNetworkCapabilities & mask;
long newImmutableCapabilities = that.mNetworkCapabilities & mask;
if (oldImmutableCapabilities != newImmutableCapabilities) {
@@ -1264,7 +1335,8 @@
&& equalsLinkBandwidths(that)
&& equalsSignalStrength(that)
&& equalsSpecifier(that)
- && equalsUids(that));
+ && equalsUids(that)
+ && equalsSSID(that));
}
@Override
@@ -1279,7 +1351,8 @@
+ (mLinkDownBandwidthKbps * 19)
+ Objects.hashCode(mNetworkSpecifier) * 23
+ (mSignalStrength * 29)
- + Objects.hashCode(mUids) * 31;
+ + Objects.hashCode(mUids) * 31
+ + Objects.hashCode(mSSID) * 37;
}
@Override
@@ -1296,6 +1369,7 @@
dest.writeParcelable((Parcelable) mNetworkSpecifier, flags);
dest.writeInt(mSignalStrength);
dest.writeArraySet(mUids);
+ dest.writeString(mSSID);
}
public static final Creator<NetworkCapabilities> CREATOR =
@@ -1313,6 +1387,7 @@
netCap.mSignalStrength = in.readInt();
netCap.mUids = (ArraySet<UidRange>) in.readArraySet(
null /* ClassLoader, null for default */);
+ netCap.mSSID = in.readString();
return netCap;
}
@Override
@@ -1363,6 +1438,10 @@
sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid);
}
+ if (null != mSSID) {
+ sb.append(" SSID: ").append(mSSID);
+ }
+
sb.append("]");
return sb.toString();
}
@@ -1392,6 +1471,31 @@
}
}
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ for (int transport : getTransportTypes()) {
+ proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
+ }
+
+ for (int capability : getCapabilities()) {
+ proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
+ }
+
+ proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
+ proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);
+
+ if (mNetworkSpecifier != null) {
+ proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
+ }
+
+ proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
+ proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
+
+ proto.end(token);
+ }
+
/**
* @hide
*/
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 1ee0ed7..16c2342 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,10 +17,13 @@
package android.net;
import android.annotation.NonNull;
+import android.net.NetworkCapabilities.NetCapability;
+import android.net.NetworkCapabilities.Transport;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.text.TextUtils;
+import android.util.proto.ProtoOutputStream;
import java.util.Objects;
import java.util.Set;
@@ -165,9 +168,6 @@
* the requested network's required capabilities. Note that when searching
* for a network to satisfy a request, all capabilities requested must be
* satisfied.
- * <p>
- * If the given capability was previously added to the list of unwanted capabilities
- * then the capability will also be removed from the list of unwanted capabilities.
*
* @param capability The capability to add.
* @return The builder to facilitate chaining
@@ -179,8 +179,7 @@
}
/**
- * Removes (if found) the given capability from this builder instance from both required
- * and unwanted capabilities lists.
+ * Removes (if found) the given capability from this builder instance.
*
* @param capability The capability to remove.
* @return The builder to facilitate chaining.
@@ -199,8 +198,7 @@
* @hide
*/
public Builder setCapabilities(NetworkCapabilities nc) {
- mNetworkCapabilities.clearAll();
- mNetworkCapabilities.combineCapabilities(nc);
+ mNetworkCapabilities.set(nc);
return this;
}
@@ -228,6 +226,7 @@
*
* @param capability The capability to add to unwanted capability list.
* @return The builder to facilitate chaining.
+ *
* @hide
*/
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
@@ -426,12 +425,64 @@
return type == Type.BACKGROUND_REQUEST;
}
+ /**
+ * @see Builder#addCapability(int)
+ */
+ public boolean hasCapability(@NetCapability int capability) {
+ return networkCapabilities.hasCapability(capability);
+ }
+
+ /**
+ * @see Builder#addUnwantedCapability(int)
+ *
+ * @hide
+ */
+ public boolean hasUnwantedCapability(@NetCapability int capability) {
+ return networkCapabilities.hasUnwantedCapability(capability);
+ }
+
+ /**
+ * @see Builder#addTransportType(int)
+ */
+ public boolean hasTransport(@Transport int transportType) {
+ return networkCapabilities.hasTransport(transportType);
+ }
+
public String toString() {
return "NetworkRequest [ " + type + " id=" + requestId +
(legacyType != ConnectivityManager.TYPE_NONE ? ", legacyType=" + legacyType : "") +
", " + networkCapabilities.toString() + " ]";
}
+ private int typeToProtoEnum(Type t) {
+ switch (t) {
+ case NONE:
+ return NetworkRequestProto.TYPE_NONE;
+ case LISTEN:
+ return NetworkRequestProto.TYPE_LISTEN;
+ case TRACK_DEFAULT:
+ return NetworkRequestProto.TYPE_TRACK_DEFAULT;
+ case REQUEST:
+ return NetworkRequestProto.TYPE_REQUEST;
+ case BACKGROUND_REQUEST:
+ return NetworkRequestProto.TYPE_BACKGROUND_REQUEST;
+ default:
+ return NetworkRequestProto.TYPE_UNKNOWN;
+ }
+ }
+
+ /** @hide */
+ public void writeToProto(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+
+ proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
+ proto.write(NetworkRequestProto.REQUEST_ID, requestId);
+ proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
+ networkCapabilities.writeToProto(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
+
+ proto.end(token);
+ }
+
public boolean equals(Object obj) {
if (obj instanceof NetworkRequest == false) return false;
NetworkRequest that = (NetworkRequest)obj;
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index b00cb48..321f971 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -26,6 +26,8 @@
* @hide
*/
public class NetworkState implements Parcelable {
+ private static final boolean SANITY_CHECK_ROAMING = false;
+
public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
public final NetworkInfo networkInfo;
@@ -47,7 +49,7 @@
// This object is an atomic view of a network, so the various components
// should always agree on roaming state.
- if (networkInfo != null && networkCapabilities != null) {
+ if (SANITY_CHECK_ROAMING && networkInfo != null && networkCapabilities != null) {
if (networkInfo.isRoaming() == networkCapabilities
.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)) {
Slog.wtf("NetworkState", "Roaming state disagreement between " + networkInfo
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 9a5d502..dc1f805 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -126,51 +126,122 @@
public native static boolean queryUserAccess(int uid, int netId);
/**
- * Convert a IPv4 address from an integer to an InetAddress.
- * @param hostAddress an int corresponding to the IPv4 address in network byte order
+ * @see #intToInet4AddressHTL(int)
+ * @deprecated Use either {@link #intToInet4AddressHTH(int)}
+ * or {@link #intToInet4AddressHTL(int)}
*/
+ @Deprecated
public static InetAddress intToInetAddress(int hostAddress) {
- byte[] addressBytes = { (byte)(0xff & hostAddress),
- (byte)(0xff & (hostAddress >> 8)),
- (byte)(0xff & (hostAddress >> 16)),
- (byte)(0xff & (hostAddress >> 24)) };
+ return intToInet4AddressHTL(hostAddress);
+ }
+
+ /**
+ * Convert a IPv4 address from an integer to an InetAddress (0x04030201 -> 1.2.3.4)
+ *
+ * <p>This method uses the higher-order int bytes as the lower-order IPv4 address bytes,
+ * which is an unusual convention. Consider {@link #intToInet4AddressHTH(int)} instead.
+ * @param hostAddress an int coding for an IPv4 address, where higher-order int byte is
+ * lower-order IPv4 address byte
+ */
+ public static InetAddress intToInet4AddressHTL(int hostAddress) {
+ return intToInet4AddressHTH(Integer.reverseBytes(hostAddress));
+ }
+
+ /**
+ * Convert a IPv4 address from an integer to an InetAddress (0x01020304 -> 1.2.3.4)
+ * @param hostAddress an int coding for an IPv4 address
+ */
+ public static InetAddress intToInet4AddressHTH(int hostAddress) {
+ byte[] addressBytes = { (byte) (0xff & (hostAddress >> 24)),
+ (byte) (0xff & (hostAddress >> 16)),
+ (byte) (0xff & (hostAddress >> 8)),
+ (byte) (0xff & hostAddress) };
try {
- return InetAddress.getByAddress(addressBytes);
+ return InetAddress.getByAddress(addressBytes);
} catch (UnknownHostException e) {
- throw new AssertionError();
+ throw new AssertionError();
}
}
/**
- * Convert a IPv4 address from an InetAddress to an integer
- * @param inetAddr is an InetAddress corresponding to the IPv4 address
- * @return the IP address as an integer in network byte order
+ * @see #inet4AddressToIntHTL(Inet4Address)
+ * @deprecated Use either {@link #inet4AddressToIntHTH(Inet4Address)}
+ * or {@link #inet4AddressToIntHTL(Inet4Address)}
*/
+ @Deprecated
public static int inetAddressToInt(Inet4Address inetAddr)
throws IllegalArgumentException {
- byte [] addr = inetAddr.getAddress();
- return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
- ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
+ return inet4AddressToIntHTL(inetAddr);
}
/**
- * Convert a network prefix length to an IPv4 netmask integer
- * @param prefixLength
- * @return the IPv4 netmask as an integer in network byte order
+ * Convert an IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x01020304)
+ *
+ * <p>This conversion can help order IP addresses: considering the ordering
+ * 192.0.2.1 < 192.0.2.2 < ..., resulting ints will follow that ordering if read as unsigned
+ * integers with {@link Integer#toUnsignedLong}.
+ * @param inetAddr is an InetAddress corresponding to the IPv4 address
+ * @return the IP address as integer
*/
+ public static int inet4AddressToIntHTH(Inet4Address inetAddr)
+ throws IllegalArgumentException {
+ byte [] addr = inetAddr.getAddress();
+ return ((addr[0] & 0xff) << 24) | ((addr[1] & 0xff) << 16)
+ | ((addr[2] & 0xff) << 8) | (addr[3] & 0xff);
+ }
+
+ /**
+ * Convert a IPv4 address from an InetAddress to an integer (1.2.3.4 -> 0x04030201)
+ *
+ * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+ * which is an unusual convention. Consider {@link #inet4AddressToIntHTH(Inet4Address)} instead.
+ * @param inetAddr is an InetAddress corresponding to the IPv4 address
+ * @return the IP address as integer
+ */
+ public static int inet4AddressToIntHTL(Inet4Address inetAddr) {
+ return Integer.reverseBytes(inet4AddressToIntHTH(inetAddr));
+ }
+
+ /**
+ * @see #prefixLengthToV4NetmaskIntHTL(int)
+ * @deprecated Use either {@link #prefixLengthToV4NetmaskIntHTH(int)}
+ * or {@link #prefixLengthToV4NetmaskIntHTL(int)}
+ */
+ @Deprecated
public static int prefixLengthToNetmaskInt(int prefixLength)
throws IllegalArgumentException {
+ return prefixLengthToV4NetmaskIntHTL(prefixLength);
+ }
+
+ /**
+ * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0xffff8000)
+ * @return the IPv4 netmask as an integer
+ */
+ public static int prefixLengthToV4NetmaskIntHTH(int prefixLength)
+ throws IllegalArgumentException {
if (prefixLength < 0 || prefixLength > 32) {
throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
}
- int value = 0xffffffff << (32 - prefixLength);
- return Integer.reverseBytes(value);
+ // (int)a << b is equivalent to a << (b & 0x1f): can't shift by 32 (-1 << 32 == -1)
+ return prefixLength == 0 ? 0 : 0xffffffff << (32 - prefixLength);
+ }
+
+ /**
+ * Convert a network prefix length to an IPv4 netmask integer (prefixLength 17 -> 0x0080ffff).
+ *
+ * <p>This method stores the higher-order IPv4 address bytes in the lower-order int bytes,
+ * which is an unusual convention. Consider {@link #prefixLengthToV4NetmaskIntHTH(int)} instead.
+ * @return the IPv4 netmask as an integer
+ */
+ public static int prefixLengthToV4NetmaskIntHTL(int prefixLength)
+ throws IllegalArgumentException {
+ return Integer.reverseBytes(prefixLengthToV4NetmaskIntHTH(prefixLength));
}
/**
* Convert a IPv4 netmask integer to a prefix length
- * @param netmask as an integer in network byte order
+ * @param netmask as an integer (0xff000000 for a /8 subnet)
* @return the network prefix length
*/
public static int netmaskIntToPrefixLength(int netmask) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 20bf996..ba5f323 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -52,6 +52,8 @@
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
import android.net.IConnectivityManager;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
@@ -72,6 +74,7 @@
import android.net.NetworkSpecifier;
import android.net.NetworkState;
import android.net.NetworkUtils;
+import android.net.NetworkWatchlistManager;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.RouteInfo;
@@ -100,6 +103,8 @@
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -123,10 +128,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
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;
@@ -137,10 +142,12 @@
import com.android.server.connectivity.DataConnectionStats;
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
+import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.LingerMonitor;
import com.android.server.connectivity.MockableSystemProperties;
+import com.android.server.connectivity.MultipathPolicyTracker;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor;
@@ -148,12 +155,15 @@
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.Tethering;
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.tethering.TetheringDependencies;
+import com.android.server.net.BaseNetdEventCallback;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.utils.PriorityDump;
import com.google.android.collect.Lists;
@@ -189,14 +199,13 @@
implements PendingIntent.OnFinished {
private static final String TAG = ConnectivityService.class.getSimpleName();
- public static final String DIAG_ARG = "--diag";
+ private static final String DIAG_ARG = "--diag";
public static final String SHORT_ARG = "--short";
- public static final String TETHERING_ARG = "tethering";
+ private static final String TETHERING_ARG = "tethering";
private static final boolean DBG = true;
private static final boolean VDBG = false;
- private static final boolean LOGD_RULES = false;
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
// TODO: create better separation between radio types and network types
@@ -229,8 +238,9 @@
private KeyStore mKeyStore;
+ @VisibleForTesting
@GuardedBy("mVpns")
- private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
+ protected final SparseArray<Vpn> mVpns = new SparseArray<>();
// TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
// a direct call to LockdownVpnTracker.isEnabled().
@@ -240,13 +250,9 @@
private LockdownVpnTracker mLockdownTracker;
final private Context mContext;
- private int mNetworkPreference;
// 0 is full bad, 100 is full good
private int mDefaultInetConditionPublished = 0;
- private boolean mTestMode;
- private static ConnectivityService sServiceInstance;
-
private INetworkManagementService mNetd;
private INetworkStatsService mStatsService;
private INetworkPolicyManager mPolicyManager;
@@ -254,9 +260,6 @@
private String mCurrentTcpBufferSizes;
- private static final int ENABLED = 1;
- private static final int DISABLED = 0;
-
private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
new Class[] { AsyncChannel.class, ConnectivityService.class, NetworkAgent.class,
NetworkAgentInfo.class });
@@ -269,7 +272,7 @@
// Don't reap networks. This should be passed when some networks have not yet been
// rematched against all NetworkRequests.
DONT_REAP
- };
+ }
private enum UnneededFor {
LINGER, // Determine whether this network is unneeded and should be lingered.
@@ -277,11 +280,6 @@
}
/**
- * used internally to change our mobile data enabled flag
- */
- private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2;
-
- /**
* used internally to clear a wakelock when transitioning
* from one net to another. Clear happens when we get a new
* network - EVENT_EXPIRE_NET_TRANSITION_WAKELOCK happens
@@ -409,6 +407,9 @@
// Handle changes in Private DNS settings.
private static final int EVENT_PRIVATE_DNS_SETTINGS_CHANGED = 37;
+ // Handle private DNS validation status updates.
+ private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
+
private static String eventName(int what) {
return sMagicDecoderRing.get(what, Integer.toString(what));
}
@@ -429,29 +430,21 @@
private int mNetTransitionWakeLockTimeout;
private final PowerManager.WakeLock mPendingIntentWakeLock;
- // track the current default http proxy - tell the world if we get a new one (real change)
- private volatile ProxyInfo mDefaultProxy = null;
- private Object mProxyLock = new Object();
- private boolean mDefaultProxyDisabled = false;
-
- // track the global proxy.
- private ProxyInfo mGlobalProxy = null;
-
- private PacManager mPacManager = null;
+ // A helper object to track the current default HTTP proxy. ConnectivityService needs to tell
+ // the world when it changes.
+ private final ProxyTracker mProxyTracker;
final private SettingsObserver mSettingsObserver;
private UserManager mUserManager;
- NetworkConfig[] mNetConfigs;
- int mNetworksDefined;
+ private NetworkConfig[] mNetConfigs;
+ private int mNetworksDefined;
// the set of network types that can only be enabled by system/sig apps
- List mProtectedNetworks;
+ private List mProtectedNetworks;
- private DataConnectionStats mDataConnectionStats;
-
- TelephonyManager mTelephonyManager;
+ private TelephonyManager mTelephonyManager;
private KeepaliveTracker mKeepaliveTracker;
private NetworkNotificationManager mNotifier;
@@ -485,32 +478,37 @@
private static final int MAX_VALIDATION_LOGS = 10;
private static class ValidationLog {
final Network mNetwork;
- final String mNetworkExtraInfo;
+ final String mName;
final ReadOnlyLocalLog mLog;
- ValidationLog(Network network, String networkExtraInfo, ReadOnlyLocalLog log) {
+ ValidationLog(Network network, String name, ReadOnlyLocalLog log) {
mNetwork = network;
- mNetworkExtraInfo = networkExtraInfo;
+ mName = name;
mLog = log;
}
}
- private final ArrayDeque<ValidationLog> mValidationLogs =
- new ArrayDeque<ValidationLog>(MAX_VALIDATION_LOGS);
+ private final ArrayDeque<ValidationLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS);
- private void addValidationLogs(ReadOnlyLocalLog log, Network network, String networkExtraInfo) {
+ private void addValidationLogs(ReadOnlyLocalLog log, Network network, String name) {
synchronized (mValidationLogs) {
while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) {
mValidationLogs.removeLast();
}
- mValidationLogs.addFirst(new ValidationLog(network, networkExtraInfo, log));
+ mValidationLogs.addFirst(new ValidationLog(network, name, log));
}
}
private final IpConnectivityLog mMetricsLog;
+ @GuardedBy("mBandwidthRequests")
+ private final SparseArray<Integer> mBandwidthRequests = new SparseArray(10);
+
@VisibleForTesting
final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
+ @VisibleForTesting
+ final MultipathPolicyTracker mMultipathPolicyTracker;
+
/**
* Implements support for the legacy "one network per network type" model.
*
@@ -565,7 +563,7 @@
throw new IllegalStateException(
"legacy list for type " + type + "already initialized");
}
- mTypeLists[type] = new ArrayList<NetworkAgentInfo>();
+ mTypeLists[type] = new ArrayList<>();
}
public boolean isTypeSupported(int type) {
@@ -668,7 +666,7 @@
}
private String naiToString(NetworkAgentInfo nai) {
- String name = (nai != null) ? nai.name() : "null";
+ String name = nai.name();
String state = (nai.networkInfo != null) ?
nai.networkInfo.getState() + "/" + nai.networkInfo.getDetailedState() :
"???/???";
@@ -700,6 +698,28 @@
}
private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker();
+ /**
+ * Helper class which parses out priority arguments and dumps sections according to their
+ * priority. If priority arguments are omitted, function calls the legacy dump command.
+ */
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+ @Override
+ public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ doDump(fd, pw, new String[] {DIAG_ARG}, asProto);
+ doDump(fd, pw, new String[] {SHORT_ARG}, asProto);
+ }
+
+ @Override
+ public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ doDump(fd, pw, args, asProto);
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args, boolean asProto) {
+ doDump(fd, pw, args, asProto);
+ }
+ };
+
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
this(context, netManager, statsService, policyManager, new IpConnectivityLog());
@@ -739,6 +759,7 @@
mPolicyManagerInternal = checkNotNull(
LocalServices.getService(NetworkPolicyManagerInternal.class),
"missing NetworkPolicyManagerInternal");
+ mProxyTracker = new ProxyTracker(context, mHandler, EVENT_PROXY_HAS_CHANGED);
mKeyStore = KeyStore.getInstance();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -820,9 +841,6 @@
}
}
- mTestMode = mSystemProperties.get("cm.test.mode").equals("true")
- && mSystemProperties.get("ro.build.type").equals("eng");
-
mTethering = makeTethering();
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
@@ -849,10 +867,8 @@
mSettingsObserver = new SettingsObserver(mContext, mHandler);
registerSettingsCallbacks();
- mDataConnectionStats = new DataConnectionStats(mContext);
- mDataConnectionStats.startMonitoring();
-
- mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED);
+ final DataConnectionStats dataConnectionStats = new DataConnectionStats(mContext);
+ dataConnectionStats.startMonitoring();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -872,6 +888,8 @@
mContext, mHandler, () -> rematchForAvoidBadWifiUpdate());
mMultinetworkPolicyTracker.start();
+ mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
+
mDnsManager = new DnsManager(mContext, mNetd, mSystemProperties);
registerPrivateDnsSettingsCallbacks();
}
@@ -883,15 +901,28 @@
public boolean isTetheringSupported() {
return ConnectivityService.this.isTetheringSupported();
}
+ @Override
+ public NetworkRequest getDefaultNetworkRequest() {
+ return mDefaultRequest;
+ }
};
return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
}
+ private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
+ final NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
+ netCap.setSingleUid(uid);
+ return netCap;
+ }
+
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
- NetworkCapabilities netCap = new NetworkCapabilities();
+ final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
if (transportType > -1) {
@@ -971,7 +1002,7 @@
throw new IllegalStateException("No free netIds");
}
- private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) {
+ private NetworkState getFilteredNetworkState(int networkType, int uid) {
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
final NetworkState state;
@@ -989,14 +1020,15 @@
state = new NetworkState(info, new LinkProperties(), capabilities,
null, null, null);
}
- filterNetworkStateForUid(state, uid, ignoreBlocked);
+ filterNetworkStateForUid(state, uid, false);
return state;
} else {
return NetworkState.EMPTY;
}
}
- private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
+ @VisibleForTesting
+ protected NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
if (network == null) {
return null;
}
@@ -1141,12 +1173,20 @@
int vpnNetId = NETID_UNSET;
synchronized (mVpns) {
final Vpn vpn = mVpns.get(user);
+ // TODO : now that capabilities contain the UID, the appliesToUid test should
+ // be removed as the satisfying test below should be enough.
if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
}
NetworkAgentInfo nai;
if (vpnNetId != NETID_UNSET) {
nai = getNetworkAgentInfoForNetId(vpnNetId);
- if (nai != null) return nai.network;
+ if (nai != null) {
+ final NetworkCapabilities requiredCaps =
+ createDefaultNetworkCapabilitiesForUid(uid);
+ if (requiredCaps.satisfiedByNetworkCapabilities(nai.networkCapabilities)) {
+ return nai.network;
+ }
+ }
}
nai = getDefaultNetwork();
if (nai != null
@@ -1186,7 +1226,7 @@
return state.networkInfo;
}
}
- final NetworkState state = getFilteredNetworkState(networkType, uid, false);
+ final NetworkState state = getFilteredNetworkState(networkType, uid);
return state.networkInfo;
}
@@ -1221,7 +1261,7 @@
public Network getNetworkForType(int networkType) {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
- NetworkState state = getFilteredNetworkState(networkType, uid, false);
+ NetworkState state = getFilteredNetworkState(networkType, uid);
if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
return state.network;
}
@@ -1258,7 +1298,7 @@
// default.
enforceAccessPermission();
- HashMap<Network, NetworkCapabilities> result = new HashMap<Network, NetworkCapabilities>();
+ HashMap<Network, NetworkCapabilities> result = new HashMap<>();
NetworkAgentInfo nai = getDefaultNetwork();
NetworkCapabilities nc = getNetworkCapabilitiesInternal(nai);
@@ -1343,7 +1383,8 @@
if (nai != null) {
synchronized (nai) {
if (nai.networkCapabilities != null) {
- return networkCapabilitiesWithoutUidsUnlessAllowed(nai.networkCapabilities,
+ return networkCapabilitiesRestrictedForCallerPermissions(
+ nai.networkCapabilities,
Binder.getCallingPid(), Binder.getCallingUid());
}
}
@@ -1357,10 +1398,14 @@
return getNetworkCapabilitiesInternal(getNetworkAgentInfoForNetwork(network));
}
- private NetworkCapabilities networkCapabilitiesWithoutUidsUnlessAllowed(
+ private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
- if (checkSettingsPermission(callerPid, callerUid)) return new NetworkCapabilities(nc);
- return new NetworkCapabilities(nc).setUids(null);
+ final NetworkCapabilities newNc = new NetworkCapabilities(nc);
+ if (!checkSettingsPermission(callerPid, callerUid)) {
+ newNc.setUids(null);
+ newNc.setSSID(null);
+ }
+ return newNc;
}
private void restrictRequestUidsForCaller(NetworkCapabilities nc) {
@@ -1406,7 +1451,8 @@
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+ final int uid = Binder.getCallingUid();
+ final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities;
if (caps != null) {
return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
} else {
@@ -1520,6 +1566,42 @@
return true;
}
+ @VisibleForTesting
+ protected final INetdEventCallback mNetdEventCallback = new BaseNetdEventCallback() {
+ @Override
+ public void onPrivateDnsValidationEvent(int netId, String ipAddress,
+ String hostname, boolean validated) {
+ try {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_PRIVATE_DNS_VALIDATION_UPDATE,
+ new PrivateDnsValidationUpdate(netId,
+ InetAddress.parseNumericAddress(ipAddress),
+ hostname, validated)));
+ } catch (IllegalArgumentException e) {
+ loge("Error parsing ip address in validation event");
+ }
+ }
+ };
+
+ @VisibleForTesting
+ protected void registerNetdEventCallback() {
+ final IIpConnectivityMetrics ipConnectivityMetrics =
+ IIpConnectivityMetrics.Stub.asInterface(
+ ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ if (ipConnectivityMetrics == null) {
+ Slog.wtf(TAG, "Missing IIpConnectivityMetrics");
+ return;
+ }
+
+ try {
+ ipConnectivityMetrics.addNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_CONNECTIVITY_SERVICE,
+ mNetdEventCallback);
+ } catch (Exception e) {
+ loge("Error registering netd callback: " + e);
+ }
+ }
+
private final INetworkPolicyListener mPolicyListener = new NetworkPolicyManager.Listener() {
@Override
public void onUidRulesChanged(int uid, int uidRules) {
@@ -1690,9 +1772,10 @@
try {
bs.noteConnectivityChanged(intent.getIntExtra(
ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
- ni != null ? ni.getState().toString() : "?");
+ ni.getState().toString());
} catch (RemoteException e) {
}
+ intent.addFlags(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
try {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL, options);
@@ -1704,6 +1787,7 @@
void systemReady() {
loadGlobalProxy();
+ registerNetdEventCallback();
synchronized (this) {
mSystemReady = true;
@@ -1776,7 +1860,7 @@
if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) {
try {
- // the call fails silently if no idletimer setup for this interface
+ // the call fails silently if no idle timer setup for this interface
mNetd.removeIdleTimer(iface);
} catch (Exception e) {
loge("Exception in removeDataActivityTracking " + e);
@@ -1785,7 +1869,7 @@
}
/**
- * Reads the network specific MTU size from reources.
+ * Reads the network specific MTU size from resources.
* and set it on it's iface.
*/
private void updateMtu(LinkProperties newLp, LinkProperties oldLp) {
@@ -1891,13 +1975,6 @@
return ret;
}
- private boolean argsContain(String[] args, String target) {
- for (String arg : args) {
- if (target.equals(arg)) return true;
- }
- return false;
- }
-
private void dumpNetworkDiagnostics(IndentingPrintWriter pw) {
final List<NetworkDiagnostics> netDiags = new ArrayList<NetworkDiagnostics>();
final long DIAG_TIME_MS = 5000;
@@ -1918,13 +1995,18 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ PriorityDump.dump(mPriorityDumper, fd, writer, args);
+ }
+
+ 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 (asProto) return;
- if (argsContain(args, DIAG_ARG)) {
+ if (ArrayUtils.contains(args, DIAG_ARG)) {
dumpNetworkDiagnostics(pw);
return;
- } else if (argsContain(args, TETHERING_ARG)) {
+ } else if (ArrayUtils.contains(args, TETHERING_ARG)) {
mTethering.dump(fd, pw, args);
return;
}
@@ -1989,12 +2071,15 @@
pw.println();
dumpAvoidBadWifiSettings(pw);
- if (argsContain(args, SHORT_ARG) == false) {
+ pw.println();
+ mMultipathPolicyTracker.dump(pw);
+
+ if (ArrayUtils.contains(args, SHORT_ARG) == false) {
pw.println();
synchronized (mValidationLogs) {
pw.println("mValidationLogs (most recent first):");
for (ValidationLog p : mValidationLogs) {
- pw.println(p.mNetwork + " - " + p.mNetworkExtraInfo);
+ pw.println(p.mNetwork + " - " + p.mName);
pw.increaseIndent();
p.mLog.dump(fd, pw, args);
pw.decreaseIndent();
@@ -2025,6 +2110,18 @@
pw.println("currently holding WakeLock for: " + (duration / 1000) + "s");
}
mWakelockLogs.reverseDump(fd, pw, args);
+
+ pw.println();
+ pw.println("bandwidth update requests (by uid):");
+ pw.increaseIndent();
+ synchronized (mBandwidthRequests) {
+ for (int i = 0; i < mBandwidthRequests.size(); i++) {
+ pw.println("[" + mBandwidthRequests.keyAt(i)
+ + "]: " + mBandwidthRequests.valueAt(i));
+ }
+ }
+ pw.decreaseIndent();
+
pw.decreaseIndent();
}
}
@@ -2146,6 +2243,7 @@
updateCapabilities(oldScore, nai, nai.networkCapabilities);
// If score has changed, rebroadcast to NetworkFactories. b/17726566
if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
+ if (valid) handleFreshlyValidatedNetwork(nai);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -2240,11 +2338,24 @@
mDefaultRequest.networkCapabilities, nai.networkCapabilities);
}
+ private void handleFreshlyValidatedNetwork(NetworkAgentInfo nai) {
+ if (nai == null) return;
+ // If the Private DNS mode is opportunistic, reprogram the DNS servers
+ // 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);
+ }
+ }
+
private void handlePrivateDnsSettingsChanged() {
final PrivateDnsConfig cfg = mDnsManager.getPrivateDnsConfig();
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
handlePerNetworkPrivateDnsConfig(nai, cfg);
+ if (networkRequiresValidation(nai)) {
+ handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
+ }
}
}
@@ -2269,6 +2380,15 @@
updateDnses(nai.linkProperties, null, nai.network.netId);
}
+ private void handlePrivateDnsValidationUpdate(PrivateDnsValidationUpdate update) {
+ NetworkAgentInfo nai = getNetworkAgentInfoForNetId(update.netId);
+ if (nai == null) {
+ return;
+ }
+ mDnsManager.updatePrivateDnsValidation(update);
+ handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
+ }
+
private void updateLingerState(NetworkAgentInfo nai, long now) {
// 1. Update the linger timer. If it's changed, reschedule or cancel the alarm.
// 2. If the network was lingering and there are now requests, unlinger it.
@@ -2326,94 +2446,107 @@
}
}
+ // This is a no-op if it's called with a message designating a network that has
+ // already been destroyed, because its reference will not be found in the relevant
+ // maps.
private void handleAsyncChannelDisconnected(Message msg) {
NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
if (nai != null) {
- if (DBG) {
- log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
- }
- // 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)
- // then they would disconnect organically, report their new state and then
- // disconnect the channel.
- if (nai.networkInfo.isConnected()) {
- nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
- null, null);
- }
- final boolean wasDefault = isDefaultNetwork(nai);
- if (wasDefault) {
- mDefaultInetConditionPublished = 0;
- // Log default network disconnection before required book-keeping.
- // Let rematchAllNetworksAndRequests() below record a new default network event
- // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
- // whose timestamps tell how long it takes to recover a default network.
- long now = SystemClock.elapsedRealtime();
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
- }
- notifyIfacesChangedForNetworkStats();
- // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
- // by other networks that are already connected. Perhaps that can be done by
- // sending all CALLBACK_LOST messages (for requests, not listens) at the end
- // of rematchAllNetworksAndRequests
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
- mKeepaliveTracker.handleStopAllKeepalives(nai,
- ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
- for (String iface : nai.linkProperties.getAllInterfaceNames()) {
- // Disable wakeup packet monitoring for each interface.
- wakeupModifyInterface(iface, nai.networkCapabilities, false);
- }
- nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
- mNetworkAgentInfos.remove(msg.replyTo);
- nai.maybeStopClat();
- 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);
- }
- // Remove all previously satisfied requests.
- for (int i = 0; i < nai.numNetworkRequests(); i++) {
- NetworkRequest request = nai.requestAt(i);
- NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
- if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
- clearNetworkForRequest(request.requestId);
- sendUpdatedScoreToFactories(request, 0);
- }
- }
- nai.clearLingerState();
- if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
- removeDataActivityTracking(nai);
- notifyLockdownVpn(nai);
- ensureNetworkTransitionWakelock(nai.name());
- }
- mLegacyTypeTracker.remove(nai, wasDefault);
- rematchAllNetworksAndRequests(null, 0);
- mLingerMonitor.noteDisconnect(nai);
- if (nai.created) {
- // Tell netd to clean up the configuration for this network
- // (routing rules, DNS, etc).
- // This may be slow as it requires a lot of netd shelling out to ip and
- // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
- // after we've rematched networks with requests which should make a potential
- // fallback network the default or requested a new network from the
- // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
- // long time.
- try {
- mNetd.removeNetwork(nai.network.netId);
- } catch (Exception e) {
- loge("Exception removing network: " + e);
- }
- mDnsManager.removeNetwork(nai.network);
- }
- synchronized (mNetworkForNetId) {
- mNetIdInUse.delete(nai.network.netId);
- }
+ disconnectAndDestroyNetwork(nai);
} else {
NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
}
}
+ // Destroys a network, remove references to it from the internal state managed by
+ // ConnectivityService, free its interfaces and clean up.
+ // Must be called on the Handler thread.
+ private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+ if (DBG) {
+ log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
+ }
+ // 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)
+ // then they would disconnect organically, report their new state and then
+ // disconnect the channel.
+ if (nai.networkInfo.isConnected()) {
+ nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+ null, null);
+ }
+ final boolean wasDefault = isDefaultNetwork(nai);
+ if (wasDefault) {
+ mDefaultInetConditionPublished = 0;
+ // Log default network disconnection before required book-keeping.
+ // Let rematchAllNetworksAndRequests() below record a new default network event
+ // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
+ // whose timestamps tell how long it takes to recover a default network.
+ long now = SystemClock.elapsedRealtime();
+ metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+ }
+ notifyIfacesChangedForNetworkStats();
+ // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
+ // by other networks that are already connected. Perhaps that can be done by
+ // sending all CALLBACK_LOST messages (for requests, not listens) at the end
+ // of rematchAllNetworksAndRequests
+ notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
+ mKeepaliveTracker.handleStopAllKeepalives(nai,
+ ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+ for (String iface : nai.linkProperties.getAllInterfaceNames()) {
+ // Disable wakeup packet monitoring for each interface.
+ wakeupModifyInterface(iface, nai.networkCapabilities, false);
+ }
+ nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+ mNetworkAgentInfos.remove(nai.messenger);
+ nai.maybeStopClat();
+ 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);
+ }
+ // Remove all previously satisfied requests.
+ for (int i = 0; i < nai.numNetworkRequests(); i++) {
+ NetworkRequest request = nai.requestAt(i);
+ NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+ if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+ clearNetworkForRequest(request.requestId);
+ sendUpdatedScoreToFactories(request, 0);
+ }
+ }
+ nai.clearLingerState();
+ if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+ removeDataActivityTracking(nai);
+ notifyLockdownVpn(nai);
+ ensureNetworkTransitionWakelock(nai.name());
+ }
+ mLegacyTypeTracker.remove(nai, wasDefault);
+ if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ updateAllVpnsCapabilities();
+ }
+ rematchAllNetworksAndRequests(null, 0);
+ mLingerMonitor.noteDisconnect(nai);
+ if (nai.created) {
+ // Tell netd to clean up the configuration for this network
+ // (routing rules, DNS, etc).
+ // This may be slow as it requires a lot of netd shelling out to ip and
+ // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
+ // after we've rematched networks with requests which should make a potential
+ // fallback network the default or requested a new network from the
+ // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
+ // long time.
+ try {
+ mNetd.removeNetwork(nai.network.netId);
+ } catch (Exception e) {
+ loge("Exception removing network: " + e);
+ }
+ mDnsManager.removeNetwork(nai.network);
+ }
+ synchronized (mNetworkForNetId) {
+ mNetIdInUse.delete(nai.network.netId);
+ }
+ }
+
// If this method proves to be too slow then we can maintain a separate
// pendingIntent => NetworkRequestInfo map.
// This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
@@ -2704,7 +2837,7 @@
if (!accept) {
// Tell the NetworkAgent to not automatically reconnect to the network.
nai.asyncChannel.sendMessage(NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
- // Teardown the nework.
+ // Teardown the network.
teardownUnneededNetwork(nai);
}
@@ -2851,6 +2984,11 @@
return ConnectivityManager.MULTIPATH_PREFERENCE_UNMETERED;
}
+ Integer networkPreference = mMultipathPolicyTracker.getMultipathPreference(network);
+ if (networkPreference != null) {
+ return networkPreference;
+ }
+
return mMultinetworkPolicyTracker.getMeteredMultipathPreference();
}
@@ -2944,6 +3082,7 @@
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
nai.networkMonitor.systemReady = true;
}
+ mMultipathPolicyTracker.start();
break;
}
case EVENT_REVALIDATE_NETWORK: {
@@ -2953,6 +3092,10 @@
case EVENT_PRIVATE_DNS_SETTINGS_CHANGED:
handlePrivateDnsSettingsChanged();
break;
+ case EVENT_PRIVATE_DNS_VALIDATION_UPDATE:
+ handlePrivateDnsValidationUpdate(
+ (PrivateDnsValidationUpdate) msg.obj);
+ break;
}
}
}
@@ -2962,8 +3105,7 @@
public int tether(String iface, String callerPkg) {
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
- final int status = mTethering.tether(iface);
- return status;
+ return mTethering.tether(iface);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -2975,8 +3117,7 @@
ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
- final int status = mTethering.untether(iface);
- return status;
+ return mTethering.untether(iface);
} else {
return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
}
@@ -3208,22 +3349,10 @@
nai.networkMonitor.forceReevaluation(uid);
}
- private ProxyInfo getDefaultProxy() {
- // this information is already available as a world read/writable jvm property
- // so this API change wouldn't have a benifit. It also breaks the passing
- // of proxy info to all the JVMs.
- // enforceAccessPermission();
- synchronized (mProxyLock) {
- ProxyInfo ret = mGlobalProxy;
- if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
- return ret;
- }
- }
-
@Override
public ProxyInfo getProxyForNetwork(Network network) {
- if (network == null) return getDefaultProxy();
- final ProxyInfo globalProxy = getGlobalProxy();
+ if (network == null) return mProxyTracker.getDefaultProxy();
+ final ProxyInfo globalProxy = mProxyTracker.getGlobalProxy();
if (globalProxy != null) return globalProxy;
if (!NetworkUtils.queryUserAccess(Binder.getCallingUid(), network.netId)) return null;
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
@@ -3237,80 +3366,10 @@
}
}
- // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
- // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
- // proxy is null then there is no proxy in place).
- private ProxyInfo canonicalizeProxyInfo(ProxyInfo proxy) {
- if (proxy != null && TextUtils.isEmpty(proxy.getHost())
- && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
- proxy = null;
- }
- return proxy;
- }
-
- // ProxyInfo equality function with a couple modifications over ProxyInfo.equals() to make it
- // better for determining if a new proxy broadcast is necessary:
- // 1. Canonicalize empty ProxyInfos to null so an empty proxy compares equal to null so as to
- // avoid unnecessary broadcasts.
- // 2. Make sure all parts of the ProxyInfo's compare true, including the host when a PAC URL
- // is in place. This is important so legacy PAC resolver (see com.android.proxyhandler)
- // changes aren't missed. The legacy PAC resolver pretends to be a simple HTTP proxy but
- // actually uses the PAC to resolve; this results in ProxyInfo's with PAC URL, host and port
- // all set.
- private boolean proxyInfoEqual(ProxyInfo a, ProxyInfo b) {
- a = canonicalizeProxyInfo(a);
- b = canonicalizeProxyInfo(b);
- // ProxyInfo.equals() doesn't check hosts when PAC URLs are present, but we need to check
- // hosts even when PAC URLs are present to account for the legacy PAC resolver.
- return Objects.equals(a, b) && (a == null || Objects.equals(a.getHost(), b.getHost()));
- }
-
- public void setGlobalProxy(ProxyInfo proxyProperties) {
+ @Override
+ public void setGlobalProxy(final ProxyInfo proxyProperties) {
enforceConnectivityInternalPermission();
-
- synchronized (mProxyLock) {
- if (proxyProperties == mGlobalProxy) return;
- if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
- if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return;
-
- String host = "";
- int port = 0;
- String exclList = "";
- String pacFileUrl = "";
- if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
- !Uri.EMPTY.equals(proxyProperties.getPacFileUrl()))) {
- if (!proxyProperties.isValid()) {
- if (DBG)
- log("Invalid proxy properties, ignoring: " + proxyProperties.toString());
- return;
- }
- mGlobalProxy = new ProxyInfo(proxyProperties);
- host = mGlobalProxy.getHost();
- port = mGlobalProxy.getPort();
- exclList = mGlobalProxy.getExclusionListAsString();
- if (!Uri.EMPTY.equals(proxyProperties.getPacFileUrl())) {
- pacFileUrl = proxyProperties.getPacFileUrl().toString();
- }
- } else {
- mGlobalProxy = null;
- }
- ContentResolver res = mContext.getContentResolver();
- final long token = Binder.clearCallingIdentity();
- try {
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
- Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
- exclList);
- Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- if (mGlobalProxy == null) {
- proxyProperties = mDefaultProxy;
- }
- sendProxyBroadcast(proxyProperties);
- }
+ mProxyTracker.setGlobalProxy(proxyProperties);
}
private void loadGlobalProxy() {
@@ -3332,20 +3391,16 @@
return;
}
- synchronized (mProxyLock) {
- mGlobalProxy = proxyProperties;
+ synchronized (mProxyTracker.mProxyLock) {
+ mProxyTracker.mGlobalProxy = proxyProperties;
}
}
}
+ @Override
+ @Nullable
public ProxyInfo getGlobalProxy() {
- // this information is already available as a world read/writable jvm property
- // so this API change wouldn't have a benifit. It also breaks the passing
- // of proxy info to all the JVMs.
- // enforceAccessPermission();
- synchronized (mProxyLock) {
- return mGlobalProxy;
- }
+ return mProxyTracker.getGlobalProxy();
}
private void handleApplyDefaultProxy(ProxyInfo proxy) {
@@ -3353,33 +3408,7 @@
&& Uri.EMPTY.equals(proxy.getPacFileUrl())) {
proxy = null;
}
- synchronized (mProxyLock) {
- if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
- if (mDefaultProxy == proxy) return; // catches repeated nulls
- if (proxy != null && !proxy.isValid()) {
- if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString());
- return;
- }
-
- // This call could be coming from the PacManager, containing the port of the local
- // proxy. If this new proxy matches the global proxy then copy this proxy to the
- // global (to get the correct local port), and send a broadcast.
- // TODO: Switch PacManager to have its own message to send back rather than
- // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
- if ((mGlobalProxy != null) && (proxy != null)
- && (!Uri.EMPTY.equals(proxy.getPacFileUrl()))
- && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
- mGlobalProxy = proxy;
- sendProxyBroadcast(mGlobalProxy);
- return;
- }
- mDefaultProxy = proxy;
-
- if (mGlobalProxy != null) return;
- if (!mDefaultProxyDisabled) {
- sendProxyBroadcast(proxy);
- }
- }
+ mProxyTracker.setDefaultProxy(proxy);
}
// If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy.
@@ -3387,17 +3416,17 @@
// the default proxy (even if it hasn't changed).
// TODO: Deprecate the broadcast extras as they aren't necessarily applicable in a multi-network
// world where an app might be bound to a non-default network.
- private void updateProxy(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo nai) {
+ private void updateProxy(LinkProperties newLp, LinkProperties oldLp) {
ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
- if (!proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
- sendProxyBroadcast(getDefaultProxy());
+ if (!ProxyTracker.proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
+ mProxyTracker.sendProxyBroadcast(mProxyTracker.getDefaultProxy());
}
}
private void handleDeprecatedGlobalHttpProxy() {
- String proxy = Settings.Global.getString(mContext.getContentResolver(),
+ final String proxy = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
@@ -3405,7 +3434,7 @@
return;
}
- String proxyHost = data[0];
+ final String proxyHost = data[0];
int proxyPort = 8080;
if (data.length > 1) {
try {
@@ -3414,27 +3443,11 @@
return;
}
}
- ProxyInfo p = new ProxyInfo(data[0], proxyPort, "");
+ final ProxyInfo p = new ProxyInfo(proxyHost, proxyPort, "");
setGlobalProxy(p);
}
}
- private void sendProxyBroadcast(ProxyInfo proxy) {
- if (proxy == null) proxy = new ProxyInfo("", 0, "");
- if (mPacManager.setCurrentProxyScriptUrl(proxy)) return;
- if (DBG) log("sending Proxy Broadcast for " + proxy);
- Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
- Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
- final long ident = Binder.clearCallingIdentity();
- try {
- mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
private static class SettingsObserver extends ContentObserver {
final private HashMap<Uri, Integer> mUriEventMap;
final private Context mContext;
@@ -3442,7 +3455,7 @@
SettingsObserver(Context context, Handler handler) {
super(null);
- mUriEventMap = new HashMap<Uri, Integer>();
+ mUriEventMap = new HashMap<>();
mContext = context;
mHandler = handler;
}
@@ -3652,6 +3665,26 @@
}
}
+ /**
+ * Ask all VPN objects 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.
+ * TODO : Fix this and call updateCapabilities inline to remove out-of-order events.
+ */
+ private void updateAllVpnsCapabilities() {
+ synchronized (mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ final Vpn vpn = mVpns.valueAt(i);
+ vpn.updateCapabilities();
+ }
+ }
+ }
+
@Override
public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -3728,7 +3761,7 @@
synchronized (mVpns) {
Vpn vpn = mVpns.get(userId);
if (vpn == null) {
- // Shouldn't happen as all codepaths that point here should have checked the Vpn
+ // 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");
return false;
@@ -3892,7 +3925,7 @@
url = String.format(url,
mTelephonyManager.getSimSerialNumber() /* ICCID */,
mTelephonyManager.getDeviceId() /* IMEI */,
- phoneNumber /* Phone numer */);
+ phoneNumber /* Phone number */);
}
return url;
@@ -4019,10 +4052,8 @@
}
};
- private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
- new HashMap<Messenger, NetworkFactoryInfo>();
- private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
- new HashMap<NetworkRequest, NetworkRequestInfo>();
+ private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = new HashMap<>();
+ private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
// Map from UID to number of NetworkRequests that UID has filed.
@@ -4126,8 +4157,17 @@
}
}
+ // This checks that the passed capabilities either do not request a specific SSID, or the
+ // calling app has permission to do so.
+ private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
+ int callerPid, int callerUid) {
+ if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
+ throw new SecurityException("Insufficient permissions to request a specific SSID");
+ }
+ }
+
private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
- final SortedSet<Integer> thresholds = new TreeSet();
+ final SortedSet<Integer> thresholds = new TreeSet<>();
synchronized (nai) {
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
if (nri.request.networkCapabilities.hasSignalStrength() &&
@@ -4136,7 +4176,7 @@
}
}
}
- return new ArrayList<Integer>(thresholds);
+ return new ArrayList<>(thresholds);
}
private void updateSignalStrengthThresholds(
@@ -4183,8 +4223,7 @@
// the default network request. This allows callers to keep track of
// the system default network.
if (type == NetworkRequest.Type.TRACK_DEFAULT) {
- networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
- networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+ networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid());
enforceAccessPermission();
} else {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4195,6 +4234,8 @@
enforceMeteredApnPolicy(networkCapabilities);
}
ensureRequestableCapabilities(networkCapabilities);
+ ensureSufficientPermissionsForRequest(networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
// Set the UID range for this request to the single UID of the requester, or to an empty
// set of UIDs if the caller has the appropriate permission and UIDs have not been set.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
@@ -4240,6 +4281,14 @@
}
if (nai != null) {
nai.asyncChannel.sendMessage(android.net.NetworkAgent.CMD_REQUEST_BANDWIDTH_UPDATE);
+ synchronized (mBandwidthRequests) {
+ final int uid = Binder.getCallingUid();
+ Integer uidReqs = mBandwidthRequests.get(uid);
+ if (uidReqs == null) {
+ uidReqs = new Integer(0);
+ }
+ mBandwidthRequests.put(uid, ++uidReqs);
+ }
return true;
}
return false;
@@ -4273,6 +4322,8 @@
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
+ ensureSufficientPermissionsForRequest(networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
ensureValidNetworkSpecifier(networkCapabilities);
restrictRequestUidsForCaller(networkCapabilities);
@@ -4328,6 +4379,8 @@
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ ensureSufficientPermissionsForRequest(networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
restrictRequestUidsForCaller(nc);
// 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
@@ -4354,6 +4407,8 @@
enforceAccessPermission();
}
ensureValidNetworkSpecifier(networkCapabilities);
+ ensureSufficientPermissionsForRequest(networkCapabilities,
+ Binder.getCallingPid(), Binder.getCallingUid());
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
restrictRequestUidsForCaller(nc);
@@ -4409,13 +4464,11 @@
*/
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForRequestId")
- private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
- new SparseArray<NetworkAgentInfo>();
+ private final SparseArray<NetworkAgentInfo> mNetworkForRequestId = new SparseArray<>();
// NOTE: Accessed on multiple threads, must be synchronized on itself.
@GuardedBy("mNetworkForNetId")
- private final SparseArray<NetworkAgentInfo> mNetworkForNetId =
- new SparseArray<NetworkAgentInfo>();
+ private final SparseArray<NetworkAgentInfo> mNetworkForNetId = new SparseArray<>();
// NOTE: Accessed on multiple threads, synchronized with mNetworkForNetId.
// An entry is first added to mNetIdInUse, prior to mNetworkForNetId, so
// there may not be a strict 1:1 correlation between the two.
@@ -4425,11 +4478,10 @@
// NetworkAgentInfo keyed off its connecting messenger
// TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays
// NOTE: Only should be accessed on ConnectivityServiceThread, except dump().
- private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos =
- new HashMap<Messenger, NetworkAgentInfo>();
+ private final HashMap<Messenger, NetworkAgentInfo> mNetworkAgentInfos = new HashMap<>();
@GuardedBy("mBlockedAppUids")
- private final HashSet<Integer> mBlockedAppUids = new HashSet();
+ private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
// Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
private final NetworkRequest mDefaultRequest;
@@ -4486,8 +4538,10 @@
synchronized (this) {
nai.networkMonitor.systemReady = mSystemReady;
}
- addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network,
- networkInfo.getExtraInfo());
+ final String extraInfo = networkInfo.getExtraInfo();
+ final String name = TextUtils.isEmpty(extraInfo)
+ ? nai.networkCapabilities.getSSID() : extraInfo;
+ addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
if (DBG) log("registerNetworkAgent " + nai);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
return nai.network.netId;
@@ -4507,13 +4561,13 @@
}
private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
- LinkProperties newLp = networkAgent.linkProperties;
+ LinkProperties newLp = new LinkProperties(networkAgent.linkProperties);
int netId = networkAgent.network.netId;
// The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
// we do anything else, make sure its LinkProperties are accurate.
if (networkAgent.clatd != null) {
- networkAgent.clatd.fixupLinkProperties(oldLp);
+ networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
}
updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
@@ -4526,16 +4580,24 @@
updateRoutes(newLp, oldLp, netId);
updateDnses(newLp, oldLp, netId);
+ // Make sure LinkProperties represents the latest private DNS status.
+ // This does not need to be done before updateDnses because the
+ // LinkProperties are not the source of the private DNS configuration.
+ // updateDnses will fetch the private DNS configuration from DnsManager.
+ mDnsManager.updatePrivateDnsStatus(netId, newLp);
// Start or stop clat accordingly to network state.
networkAgent.updateClat(mNetd);
if (isDefaultNetwork(networkAgent)) {
handleApplyDefaultProxy(newLp.getHttpProxy());
} else {
- updateProxy(newLp, oldLp, networkAgent);
+ updateProxy(newLp, oldLp);
}
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
+ synchronized (networkAgent) {
+ networkAgent.linkProperties = newLp;
+ }
notifyIfacesChangedForNetworkStats();
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
@@ -4544,7 +4606,7 @@
}
private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
- // Marks are only available on WiFi interaces. Checking for
+ // Marks are only available on WiFi interfaces. Checking for
// marks on unsupported interfaces is harmless.
if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return;
@@ -4576,7 +4638,7 @@
private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
NetworkCapabilities caps) {
- CompareResult<String> interfaceDiff = new CompareResult<String>(
+ CompareResult<String> interfaceDiff = new CompareResult<>(
oldLp != null ? oldLp.getAllInterfaceNames() : null,
newLp != null ? newLp.getAllInterfaceNames() : null);
for (String iface : interfaceDiff.added) {
@@ -4611,7 +4673,7 @@
// add routes before removing old in case it helps with continuous connectivity
- // do this twice, adding non-nexthop routes first, then routes they are dependent on
+ // do this twice, adding non-next-hop routes first, then routes they are dependent on
for (RouteInfo route : routeDiff.added) {
if (route.hasGateway()) continue;
if (VDBG) log("Adding Route [" + route + "] to network " + netId);
@@ -4683,7 +4745,12 @@
*/
private NetworkCapabilities mixInCapabilities(NetworkAgentInfo nai, NetworkCapabilities nc) {
// Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
+ // Don't complain for VPNs since they're not driven by requests and there is no risk of
+ // causing a connect/teardown loop.
+ // TODO: remove this altogether and make it the responsibility of the NetworkFactories to
+ // avoid connect/teardown loops.
if (nai.everConnected &&
+ !nai.isVPN() &&
!nai.networkCapabilities.satisfiedByImmutableNetworkCapabilities(nc)) {
// TODO: consider not complaining when a network agent degrades its capabilities if this
// does not cause any request (that is not a listen) currently matching that agent to
@@ -4786,12 +4853,7 @@
if (!newNc.hasTransport(TRANSPORT_VPN)) {
// Tell VPNs about updated capabilities, since they may need to
// bubble those changes through.
- synchronized (mVpns) {
- for (int i = 0; i < mVpns.size(); i++) {
- final Vpn vpn = mVpns.valueAt(i);
- vpn.updateCapabilities();
- }
- }
+ updateAllVpnsCapabilities();
}
}
@@ -4920,7 +4982,7 @@
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
// networkAgent can't be null as it has been accessed a few lines above.
- final NetworkCapabilities nc = networkCapabilitiesWithoutUidsUnlessAllowed(
+ final NetworkCapabilities nc = networkCapabilitiesRestrictedForCallerPermissions(
networkAgent.networkCapabilities, nri.mPid, nri.mUid);
putParcelable(bundle, nc);
break;
@@ -5064,8 +5126,8 @@
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
- ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<NetworkAgentInfo>();
- ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<NetworkRequestInfo>();
+ ArrayList<NetworkAgentInfo> affectedNetworks = new ArrayList<>();
+ ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
NetworkCapabilities nc = newNetwork.networkCapabilities;
if (VDBG) log(" network has: " + nc);
for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -5115,7 +5177,7 @@
keep = true;
// Tell NetworkFactories about the new score, so they can stop
// trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have alot of requests for this
+ // TODO - this could get expensive if we have a lot of requests for this
// network. Think about if there is a way to reduce this. Push
// netid->request mapping to each factory?
sendUpdatedScoreToFactories(nri.request, score);
@@ -5236,7 +5298,7 @@
// This has to happen after the notifyNetworkCallbacks as that tickles each
// ConnectivityManager instance so that legacy requests correctly bind dns
- // requests to this network. The legacy users are listening for this bcast
+ // requests to this network. The legacy users are listening for this broadcast
// and will generally do a dns request so they can ensureRouteToHost and if
// they do that before the callbacks happen they'll use the default network.
//
@@ -5301,7 +5363,7 @@
// TODO: This may get slow. The "changed" parameter is provided for future optimization
// to avoid the slowness. It is not simply enough to process just "changed", for
// example in the case where "changed"'s score decreases and another network should begin
- // satifying a NetworkRequest that "changed" currently satisfies.
+ // satisfying a NetworkRequest that "changed" currently satisfies.
// Optimization: Only reprocess "changed" if its score improved. This is safe because it
// can only add more NetworkRequests satisfied by "changed", and this is exactly what
@@ -5412,11 +5474,12 @@
if (networkAgent.isVPN()) {
// Temporarily disable the default proxy (not global).
- synchronized (mProxyLock) {
- if (!mDefaultProxyDisabled) {
- mDefaultProxyDisabled = true;
- if (mGlobalProxy == null && mDefaultProxy != null) {
- sendProxyBroadcast(null);
+ synchronized (mProxyTracker.mProxyLock) {
+ if (!mProxyTracker.mDefaultProxyDisabled) {
+ mProxyTracker.mDefaultProxyDisabled = true;
+ if (mProxyTracker.mGlobalProxy == null
+ && mProxyTracker.mDefaultProxy != null) {
+ mProxyTracker.sendProxyBroadcast(null);
}
}
}
@@ -5441,19 +5504,21 @@
} else if (state == NetworkInfo.State.DISCONNECTED) {
networkAgent.asyncChannel.disconnect();
if (networkAgent.isVPN()) {
- synchronized (mProxyLock) {
- if (mDefaultProxyDisabled) {
- mDefaultProxyDisabled = false;
- if (mGlobalProxy == null && mDefaultProxy != null) {
- sendProxyBroadcast(mDefaultProxy);
+ synchronized (mProxyTracker.mProxyLock) {
+ if (mProxyTracker.mDefaultProxyDisabled) {
+ mProxyTracker.mDefaultProxyDisabled = false;
+ if (mProxyTracker.mGlobalProxy == null
+ && mProxyTracker.mDefaultProxy != null) {
+ mProxyTracker.sendProxyBroadcast(mProxyTracker.mDefaultProxy);
}
}
}
updateUids(networkAgent, networkAgent.networkCapabilities, null);
}
+ disconnectAndDestroyNetwork(networkAgent);
} else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
state == NetworkInfo.State.SUSPENDED) {
- // going into or coming out of SUSPEND: rescore and notify
+ // going into or coming out of SUSPEND: re-score and notify
if (networkAgent.getCurrentScore() != oldScore) {
rematchAllNetworksAndRequests(networkAgent, oldScore);
}
@@ -5713,6 +5778,17 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
}
+ @Override
+ public byte[] getNetworkWatchlistConfigHash() {
+ NetworkWatchlistManager nwm = mContext.getSystemService(NetworkWatchlistManager.class);
+ if (nwm == null) {
+ loge("Unable to get NetworkWatchlistManager");
+ return null;
+ }
+ // Redirect it to network watchlist service to access watchlist file and calculate hash.
+ return nwm.getWatchlistConfigHash();
+ }
+
@VisibleForTesting
public NetworkMonitor createNetworkMonitor(Context context, Handler handler,
NetworkAgentInfo nai, NetworkRequest defaultRequest) {
@@ -5752,4 +5828,61 @@
private static int encodeBool(boolean b) {
return b ? 1 : 0;
}
+
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+ }
+
+ private class ShellCmd extends ShellCommand {
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch (cmd) {
+ case "airplane-mode":
+ final String action = getNextArg();
+ if ("enable".equals(action)) {
+ setAirplaneMode(true);
+ return 0;
+ } else if ("disable".equals(action)) {
+ setAirplaneMode(false);
+ return 0;
+ } else if (action == null) {
+ final ContentResolver cr = mContext.getContentResolver();
+ final int enabled = Settings.Global.getInt(cr,
+ Settings.Global.AIRPLANE_MODE_ON);
+ pw.println(enabled == 0 ? "disabled" : "enabled");
+ return 0;
+ } else {
+ onHelp();
+ return -1;
+ }
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (Exception e) {
+ pw.println(e);
+ }
+ return -1;
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Connectivity service commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println(" airplane-mode [enable|disable]");
+ pw.println(" Turn airplane mode on or off.");
+ pw.println(" airplane-mode");
+ pw.println(" Get airplane mode.");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 2a361a0..c0beb37 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -16,7 +16,7 @@
package com.android.server.connectivity;
-import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
@@ -24,6 +24,7 @@
import static android.provider.Settings.Global.DNS_RESOLVER_MAX_SAMPLES;
import static android.provider.Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS;
import static android.provider.Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT;
+import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
@@ -37,10 +38,10 @@
import android.net.dns.ResolvUtil;
import android.os.Binder;
import android.os.INetworkManagementService;
-import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.Pair;
import android.util.Slog;
import com.android.server.connectivity.MockableSystemProperties;
@@ -49,9 +50,14 @@
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import java.util.stream.Collectors;
+import java.util.Set;
import java.util.StringJoiner;
@@ -110,6 +116,7 @@
*/
public class DnsManager {
private static final String TAG = DnsManager.class.getSimpleName();
+ private static final PrivateDnsConfig PRIVATE_DNS_OFF = new PrivateDnsConfig();
/* Defaults for resolver parameters. */
private static final int DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800;
@@ -178,16 +185,107 @@
public static Uri[] getPrivateDnsSettingsUris() {
return new Uri[]{
+ Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE),
Settings.Global.getUriFor(PRIVATE_DNS_MODE),
Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
};
}
+ public static class PrivateDnsValidationUpdate {
+ final public int netId;
+ final public InetAddress ipAddress;
+ final public String hostname;
+ final public boolean validated;
+
+ public PrivateDnsValidationUpdate(int netId, InetAddress ipAddress,
+ String hostname, boolean validated) {
+ this.netId = netId;
+ this.ipAddress = ipAddress;
+ this.hostname = hostname;
+ this.validated = validated;
+ }
+ }
+
+ private static class PrivateDnsValidationStatuses {
+ enum ValidationStatus {
+ IN_PROGRESS,
+ FAILED,
+ SUCCEEDED
+ }
+
+ // Validation statuses of <hostname, ipAddress> pairs for a single netId
+ // Caution : not thread-safe. As mentioned in the top file comment, all
+ // methods of this class must only be called on ConnectivityService's thread.
+ private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
+
+ private PrivateDnsValidationStatuses() {
+ mValidationMap = new HashMap<>();
+ }
+
+ private boolean hasValidatedServer() {
+ for (ValidationStatus status : mValidationMap.values()) {
+ if (status == ValidationStatus.SUCCEEDED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void updateTrackedDnses(String[] ipAddresses, String hostname) {
+ Set<Pair<String, InetAddress>> latestDnses = new HashSet<>();
+ for (String ipAddress : ipAddresses) {
+ try {
+ latestDnses.add(new Pair(hostname,
+ InetAddress.parseNumericAddress(ipAddress)));
+ } catch (IllegalArgumentException e) {}
+ }
+ // Remove <hostname, ipAddress> pairs that should not be tracked.
+ for (Iterator<Map.Entry<Pair<String, InetAddress>, ValidationStatus>> it =
+ mValidationMap.entrySet().iterator(); it.hasNext(); ) {
+ Map.Entry<Pair<String, InetAddress>, ValidationStatus> entry = it.next();
+ if (!latestDnses.contains(entry.getKey())) {
+ it.remove();
+ }
+ }
+ // Add new <hostname, ipAddress> pairs that should be tracked.
+ for (Pair<String, InetAddress> p : latestDnses) {
+ if (!mValidationMap.containsKey(p)) {
+ mValidationMap.put(p, ValidationStatus.IN_PROGRESS);
+ }
+ }
+ }
+
+ private void updateStatus(PrivateDnsValidationUpdate update) {
+ Pair<String, InetAddress> p = new Pair(update.hostname,
+ update.ipAddress);
+ if (!mValidationMap.containsKey(p)) {
+ return;
+ }
+ if (update.validated) {
+ mValidationMap.put(p, ValidationStatus.SUCCEEDED);
+ } else {
+ mValidationMap.put(p, ValidationStatus.FAILED);
+ }
+ }
+
+ private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
+ lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
+ mValidationMap.forEach((key, value) -> {
+ if (value == ValidationStatus.SUCCEEDED) {
+ lp.addValidatedPrivateDnsServer(key.second);
+ }
+ });
+ return lp;
+ }
+ }
+
private final Context mContext;
private final ContentResolver mContentResolver;
private final INetworkManagementService mNMS;
private final MockableSystemProperties mSystemProperties;
+ // TODO: Replace these Maps with SparseArrays.
private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
+ private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
private int mNumDnsEntries;
private int mSampleValidity;
@@ -203,6 +301,7 @@
mNMS = nms;
mSystemProperties = sp;
mPrivateDnsMap = new HashMap<>();
+ mPrivateDnsValidationMap = new HashMap<>();
// TODO: Create and register ContentObservers to track every setting
// used herein, posting messages to respond to changes.
@@ -214,6 +313,7 @@
public void removeNetwork(Network network) {
mPrivateDnsMap.remove(network.netId);
+ mPrivateDnsValidationMap.remove(network.netId);
}
public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) {
@@ -223,6 +323,36 @@
: mPrivateDnsMap.remove(network.netId);
}
+ public void updatePrivateDnsStatus(int netId, LinkProperties lp) {
+ // Use the PrivateDnsConfig data pushed to this class instance
+ // from ConnectivityService.
+ final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
+ PRIVATE_DNS_OFF);
+
+ final boolean useTls = privateDnsCfg.useTls;
+ final PrivateDnsValidationStatuses statuses =
+ useTls ? mPrivateDnsValidationMap.get(netId) : null;
+ final boolean validated = (null != statuses) && statuses.hasValidatedServer();
+ final boolean strictMode = privateDnsCfg.inStrictMode();
+ final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
+ final boolean usingPrivateDns = strictMode || validated;
+
+ lp.setUsePrivateDns(usingPrivateDns);
+ lp.setPrivateDnsServerName(tlsHostname);
+ if (usingPrivateDns && null != statuses) {
+ statuses.fillInValidatedPrivateDns(lp);
+ } else {
+ lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
+ }
+ }
+
+ public void updatePrivateDnsValidation(PrivateDnsValidationUpdate update) {
+ final PrivateDnsValidationStatuses statuses =
+ mPrivateDnsValidationMap.get(update.netId);
+ if (statuses == null) return;
+ statuses.updateStatus(update);
+ }
+
public void setDnsConfigurationForNetwork(
int netId, LinkProperties lp, boolean isDefaultNetwork) {
final String[] assignedServers = NetworkUtils.makeStrings(lp.getDnsServers());
@@ -238,10 +368,11 @@
//
// At this time we do not attempt to enable Private DNS on non-Internet
// networks like IMS.
- final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId);
+ final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId,
+ PRIVATE_DNS_OFF);
- final boolean useTls = (privateDnsCfg != null) && privateDnsCfg.useTls;
- final boolean strictMode = (privateDnsCfg != null) && privateDnsCfg.inStrictMode();
+ final boolean useTls = privateDnsCfg.useTls;
+ final boolean strictMode = privateDnsCfg.inStrictMode();
final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
final String[] tlsServers =
strictMode ? NetworkUtils.makeStrings(
@@ -251,6 +382,17 @@
: useTls ? assignedServers // Opportunistic
: new String[0]; // Off
+ // Prepare to track the validation status of the DNS servers in the
+ // resolver config when private DNS is in opportunistic or strict mode.
+ if (useTls) {
+ if (!mPrivateDnsValidationMap.containsKey(netId)) {
+ mPrivateDnsValidationMap.put(netId, new PrivateDnsValidationStatuses());
+ }
+ mPrivateDnsValidationMap.get(netId).updateTrackedDnses(tlsServers, tlsHostname);
+ } else {
+ mPrivateDnsValidationMap.remove(netId);
+ }
+
Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
@@ -345,8 +487,10 @@
}
private static String getPrivateDnsMode(ContentResolver cr) {
- final String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
- return !TextUtils.isEmpty(mode) ? mode : PRIVATE_DNS_DEFAULT_MODE;
+ String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
+ if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_DEFAULT_MODE_FALLBACK;
+ return mode;
}
private static String getStringSetting(ContentResolver cr, String which) {
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index fceacba..f523d59 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -224,15 +224,14 @@
}
/**
- * Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork.
+ * Copies the stacked clat link in oldLp, if any, to the passed LinkProperties.
* This is necessary because the LinkProperties in mNetwork come from the transport layer, which
* has no idea that 464xlat is running on top of it.
*/
- public void fixupLinkProperties(LinkProperties oldLp) {
+ public void fixupLinkProperties(LinkProperties oldLp, LinkProperties lp) {
if (!isRunning()) {
return;
}
- LinkProperties lp = mNetwork.linkProperties;
if (lp == null || lp.getAllInterfaceNames().contains(mIface)) {
return;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 0d935db..36a2476 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -23,8 +23,10 @@
import android.content.Intent;
import android.content.res.Resources;
import android.net.NetworkCapabilities;
+import android.net.wifi.WifiInfo;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -130,16 +132,17 @@
final String tag = tagFor(id);
final int eventId = notifyType.eventId;
final int transportType;
- final String extraInfo;
+ final String name;
if (nai != null) {
transportType = getFirstTransportType(nai);
- extraInfo = nai.networkInfo.getExtraInfo();
+ final String extraInfo = nai.networkInfo.getExtraInfo();
+ name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSSID() : extraInfo;
// Only notify for Internet-capable networks.
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
} else {
// Legacy notifications.
transportType = TRANSPORT_CELLULAR;
- extraInfo = null;
+ name = null;
}
// Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -156,9 +159,8 @@
if (DBG) {
Slog.d(TAG, String.format(
- "showNotification tag=%s event=%s transport=%s extraInfo=%s highPrioriy=%s",
- tag, nameOf(eventId), getTransportName(transportType), extraInfo,
- highPriority));
+ "showNotification tag=%s event=%s transport=%s name=%s highPriority=%s",
+ tag, nameOf(eventId), getTransportName(transportType), name, highPriority));
}
Resources r = Resources.getSystem();
@@ -176,7 +178,8 @@
switch (transportType) {
case TRANSPORT_WIFI:
title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+ details = r.getString(R.string.network_available_sign_in_detailed,
+ WifiInfo.removeDoubleQuotes(nai.networkCapabilities.getSSID()));
break;
case TRANSPORT_CELLULAR:
title = r.getString(R.string.network_available_sign_in, 0);
@@ -186,7 +189,7 @@
break;
default:
title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+ details = r.getString(R.string.network_available_sign_in_detailed, name);
break;
}
} else if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index d578e95..e471c7d 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -202,7 +202,9 @@
// Only using the first package name. There may be multiple names if multiple
// apps share the same UID, but in that case they also share permissions so
// querying with any of the names will return the same results.
- final PackageInfo app = mPackageManager.getPackageInfo(names[0], GET_PERMISSIONS);
+ int userId = UserHandle.getUserId(uid);
+ final PackageInfo app = mPackageManager.getPackageInfoAsUser(
+ names[0], GET_PERMISSIONS, userId);
return hasUseBackgroundNetworksPermission(app);
} catch (NameNotFoundException e) {
// App not found.
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
new file mode 100644
index 0000000..dc65e1e
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -0,0 +1,256 @@
+/**
+ * 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;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Proxy;
+import android.net.ProxyInfo;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.Objects;
+
+/**
+ * A class to handle proxy for ConnectivityService.
+ *
+ * @hide
+ */
+public class ProxyTracker {
+ private static final String TAG = ProxyTracker.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ @NonNull
+ private final Context mContext;
+
+ // TODO : make this private and import as much managing logic from ConnectivityService as
+ // possible
+ @NonNull
+ public final Object mProxyLock = new Object();
+ // The global proxy is the proxy that is set device-wide, overriding any network-specific
+ // proxy. Note however that proxies are hints ; the system does not enforce their use. Hence
+ // this value is only for querying.
+ @Nullable
+ @GuardedBy("mProxyLock")
+ public ProxyInfo mGlobalProxy = null;
+ // The default proxy is the proxy that applies to no particular network if the global proxy
+ // is not set. Individual networks have their own settings that override this. This member
+ // is set through setDefaultProxy, which is called when the default network changes proxies
+ // in its LinkProperties, or when ConnectivityService switches to a new default network, or
+ // when PacManager resolves the proxy.
+ @Nullable
+ @GuardedBy("mProxyLock")
+ public volatile ProxyInfo mDefaultProxy = null;
+ // Whether the default proxy is disabled. TODO : make this mDefaultProxyEnabled
+ @GuardedBy("mProxyLock")
+ public boolean mDefaultProxyDisabled = false;
+
+ // The object responsible for Proxy Auto Configuration (PAC).
+ @NonNull
+ private final PacManager mPacManager;
+
+ public ProxyTracker(@NonNull final Context context,
+ @NonNull final Handler connectivityServiceInternalHandler, final int pacChangedEvent) {
+ mContext = context;
+ mPacManager = new PacManager(context, connectivityServiceInternalHandler, pacChangedEvent);
+ }
+
+ // Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present
+ // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
+ // proxy is null then there is no proxy in place).
+ @Nullable
+ private static ProxyInfo canonicalizeProxyInfo(@Nullable final ProxyInfo proxy) {
+ if (proxy != null && TextUtils.isEmpty(proxy.getHost())
+ && (proxy.getPacFileUrl() == null || Uri.EMPTY.equals(proxy.getPacFileUrl()))) {
+ return null;
+ }
+ return proxy;
+ }
+
+ // ProxyInfo equality functions with a couple modifications over ProxyInfo.equals() to make it
+ // better for determining if a new proxy broadcast is necessary:
+ // 1. Canonicalize empty ProxyInfos to null so an empty proxy compares equal to null so as to
+ // avoid unnecessary broadcasts.
+ // 2. Make sure all parts of the ProxyInfo's compare true, including the host when a PAC URL
+ // is in place. This is important so legacy PAC resolver (see com.android.proxyhandler)
+ // changes aren't missed. The legacy PAC resolver pretends to be a simple HTTP proxy but
+ // actually uses the PAC to resolve; this results in ProxyInfo's with PAC URL, host and port
+ // all set.
+ public static boolean proxyInfoEqual(@Nullable final ProxyInfo a, @Nullable final ProxyInfo b) {
+ final ProxyInfo pa = canonicalizeProxyInfo(a);
+ final ProxyInfo pb = canonicalizeProxyInfo(b);
+ // ProxyInfo.equals() doesn't check hosts when PAC URLs are present, but we need to check
+ // hosts even when PAC URLs are present to account for the legacy PAC resolver.
+ return Objects.equals(pa, pb) && (pa == null || Objects.equals(pa.getHost(), pb.getHost()));
+ }
+
+ /**
+ * Gets the default system-wide proxy.
+ *
+ * This will return the global proxy if set, otherwise the default proxy if in use. Note
+ * that this is not necessarily the proxy that any given process should use, as the right
+ * proxy for a process is the proxy for the network this process will use, which may be
+ * different from this value. This value is simply the default in case there is no proxy set
+ * in the network that will be used by a specific process.
+ * @return The default system-wide proxy or null if none.
+ */
+ @Nullable
+ public ProxyInfo getDefaultProxy() {
+ // This information is already available as a world read/writable jvm property.
+ synchronized (mProxyLock) {
+ final ProxyInfo ret = mGlobalProxy;
+ if ((ret == null) && !mDefaultProxyDisabled) return mDefaultProxy;
+ return ret;
+ }
+ }
+
+ /**
+ * Gets the global proxy.
+ *
+ * @return The global proxy or null if none.
+ */
+ @Nullable
+ public ProxyInfo getGlobalProxy() {
+ // This information is already available as a world read/writable jvm property.
+ synchronized (mProxyLock) {
+ return mGlobalProxy;
+ }
+ }
+
+ /**
+ * Sends the system broadcast informing apps about a new proxy configuration.
+ *
+ * Confusingly this method also sets the PAC file URL. TODO : separate this, it has nothing
+ * to do in a "sendProxyBroadcast" method.
+ * @param proxyInfo the proxy spec, or null for no proxy.
+ */
+ // TODO : make the argument NonNull final and the method private
+ public void sendProxyBroadcast(@Nullable ProxyInfo proxyInfo) {
+ if (proxyInfo == null) proxyInfo = new ProxyInfo("", 0, "");
+ if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)) return;
+ if (DBG) Slog.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);
+ intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxyInfo);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ /**
+ * Sets the global proxy in memory. Also writes the values to the global settings of the device.
+ *
+ * @param proxyInfo the proxy spec, or null for no proxy.
+ */
+ public void setGlobalProxy(@Nullable ProxyInfo proxyInfo) {
+ synchronized (mProxyLock) {
+ // ProxyInfo#equals is not commutative :( and is public API, so it can't be fixed.
+ if (proxyInfo == mGlobalProxy) return;
+ if (proxyInfo != null && proxyInfo.equals(mGlobalProxy)) return;
+ if (mGlobalProxy != null && mGlobalProxy.equals(proxyInfo)) return;
+
+ final String host;
+ final int port;
+ final String exclList;
+ final String pacFileUrl;
+ 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);
+ return;
+ }
+ mGlobalProxy = new ProxyInfo(proxyInfo);
+ host = mGlobalProxy.getHost();
+ port = mGlobalProxy.getPort();
+ exclList = mGlobalProxy.getExclusionListAsString();
+ pacFileUrl = Uri.EMPTY.equals(proxyInfo.getPacFileUrl())
+ ? "" : proxyInfo.getPacFileUrl().toString();
+ } else {
+ host = "";
+ port = 0;
+ exclList = "";
+ pacFileUrl = "";
+ mGlobalProxy = null;
+ }
+ final ContentResolver res = mContext.getContentResolver();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ exclList);
+ Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
+ sendProxyBroadcast(mGlobalProxy == null ? mDefaultProxy : proxyInfo);
+ }
+ }
+
+ /**
+ * Sets the default proxy for the device.
+ *
+ * The default proxy is the proxy used for networks that do not have a specific proxy.
+ * @param proxyInfo the proxy spec, or null for no proxy.
+ */
+ public void setDefaultProxy(@Nullable ProxyInfo proxyInfo) {
+ synchronized (mProxyLock) {
+ if (mDefaultProxy != null && mDefaultProxy.equals(proxyInfo)) {
+ return;
+ }
+ if (mDefaultProxy == proxyInfo) return; // catches repeated nulls
+ if (proxyInfo != null && !proxyInfo.isValid()) {
+ if (DBG) Slog.d(TAG, "Invalid proxy properties, ignoring: " + proxyInfo);
+ return;
+ }
+
+ // This call could be coming from the PacManager, containing the port of the local
+ // proxy. If this new proxy matches the global proxy then copy this proxy to the
+ // global (to get the correct local port), and send a broadcast.
+ // TODO: Switch PacManager to have its own message to send back rather than
+ // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy.
+ if ((mGlobalProxy != null) && (proxyInfo != null)
+ && (!Uri.EMPTY.equals(proxyInfo.getPacFileUrl()))
+ && proxyInfo.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) {
+ mGlobalProxy = proxyInfo;
+ sendProxyBroadcast(mGlobalProxy);
+ return;
+ }
+ mDefaultProxy = proxyInfo;
+
+ if (mGlobalProxy != null) return;
+ if (!mDefaultProxyDisabled) {
+ sendProxyBroadcast(proxyInfo);
+ }
+ }
+ }
+}
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index 703b415..dec8ca2 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -49,4 +49,14 @@
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
}
+
+ /**
+ * Returns true if the APF interpreter advertises support for the data buffer access opcodes
+ * LDDW and STDW.
+ *
+ * Full LDDW and STDW support is present from APFv4 on.
+ */
+ public boolean hasDataAccess() {
+ return apfVersionSupported >= 4;
+ }
}
diff --git a/services/net/java/android/net/util/MultinetworkPolicyTracker.java b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
index 424e40d..30c5cd9 100644
--- a/services/net/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/services/net/java/android/net/util/MultinetworkPolicyTracker.java
@@ -122,6 +122,7 @@
return mAvoidBadWifi;
}
+ // TODO: move this to MultipathPolicyTracker.
public int getMeteredMultipathPreference() {
return mMeteredMultipathPreference;
}
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 9191bd3..8160924 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.Os;
@@ -70,11 +71,17 @@
private IpSecService mMockIpSecService;
private IpSecManager mIpSecManager;
+ private MockContext mMockContext = new MockContext() {
+ @Override
+ public String getOpPackageName() {
+ return "fooPackage";
+ }
+ };
@Before
public void setUp() throws Exception {
mMockIpSecService = mock(IpSecService.class);
- mIpSecManager = new IpSecManager(mMockIpSecService);
+ mIpSecManager = new IpSecManager(mMockContext, mMockIpSecService);
}
/*
@@ -255,7 +262,7 @@
new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
when(mMockIpSecService.createTunnelInterface(
eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
- anyObject(), anyObject()))
+ anyObject(), anyObject(), anyString()))
.thenReturn(dummyResponse);
IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
@@ -273,7 +280,7 @@
assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());
tunnelIntf.close();
- verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
+ verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID), anyString());
}
@Test
@@ -281,12 +288,16 @@
IpSecManager.IpSecTunnelInterface tunnelIntf =
createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);
- tunnelIntf.addAddress(VTI_INNER_ADDRESS);
+ tunnelIntf.addAddress(VTI_INNER_ADDRESS.getAddress(),
+ VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
- tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
+ tunnelIntf.removeAddress(VTI_INNER_ADDRESS.getAddress(),
+ VTI_INNER_ADDRESS.getPrefixLength());
verify(mMockIpSecService)
- .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
+ .addAddressToTunnelInterface(
+ eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS), anyString());
}
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/android/net/LinkPropertiesTest.java b/tests/net/java/android/net/LinkPropertiesTest.java
index f3c22a5..9695e9a 100644
--- a/tests/net/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/java/android/net/LinkPropertiesTest.java
@@ -27,6 +27,7 @@
import android.net.LinkProperties.CompareResult;
import android.net.LinkProperties.ProvisioningChange;
import android.net.RouteInfo;
+import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.system.OsConstants;
@@ -82,6 +83,9 @@
assertTrue(source.isIdenticalPrivateDns(target));
assertTrue(target.isIdenticalPrivateDns(source));
+ assertTrue(source.isIdenticalValidatedPrivateDnses(target));
+ assertTrue(target.isIdenticalValidatedPrivateDnses(source));
+
assertTrue(source.isIdenticalRoutes(target));
assertTrue(target.isIdenticalRoutes(source));
@@ -784,4 +788,35 @@
assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
}
+
+ @Test
+ public void testLinkPropertiesParcelable() {
+ LinkProperties source = new LinkProperties();
+ source.setInterfaceName(NAME);
+ // set 2 link addresses
+ source.addLinkAddress(LINKADDRV4);
+ source.addLinkAddress(LINKADDRV6);
+ // set 2 dnses
+ source.addDnsServer(DNS1);
+ source.addDnsServer(DNS2);
+ // set 2 gateways
+ source.addRoute(new RouteInfo(GATEWAY1));
+ source.addRoute(new RouteInfo(GATEWAY2));
+ // set 2 validated private dnses
+ source.addValidatedPrivateDnsServer(DNS6);
+ source.addValidatedPrivateDnsServer(GATEWAY61);
+
+ source.setMtu(MTU);
+
+ Parcel p = Parcel.obtain();
+ source.writeToParcel(p, /* flags */ 0);
+ p.setDataPosition(0);
+ final byte[] marshalled = p.marshall();
+ p = Parcel.obtain();
+ p.unmarshall(marshalled, 0, marshalled.length);
+ p.setDataPosition(0);
+ LinkProperties dest = LinkProperties.CREATOR.createFromParcel(p);
+
+ assertEquals(source, dest);
+ }
}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 0696592..b40921f 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -19,7 +19,6 @@
import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
@@ -40,12 +39,14 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
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;
@@ -54,6 +55,9 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class NetworkCapabilitiesTest {
+ private static final String TEST_SSID = "TEST_SSID";
+ private static final String DIFFERENT_TEST_SSID = "DIFFERENT_TEST_SSID";
+
@Test
public void testMaybeMarkCapabilitiesRestricted() {
// verify EIMS is restricted
@@ -154,14 +158,6 @@
assertEquals("", nc1.describeImmutableDifferences(nc2));
assertEquals("", nc1.describeImmutableDifferences(nc1));
- // DUN changing (http://b/65257223)
- nc1 = new NetworkCapabilities()
- .addCapability(NET_CAPABILITY_DUN)
- .addCapability(NET_CAPABILITY_INTERNET);
- nc2 = new NetworkCapabilities().addCapability(NET_CAPABILITY_INTERNET);
- assertEquals("", nc1.describeImmutableDifferences(nc2));
- assertEquals("", nc1.describeImmutableDifferences(nc1));
-
// Immutable capability changing
nc1 = new NetworkCapabilities()
.addCapability(NET_CAPABILITY_INTERNET)
@@ -268,6 +264,8 @@
.addCapability(NET_CAPABILITY_EIMS)
.addCapability(NET_CAPABILITY_NOT_METERED);
assertEqualsThroughMarshalling(netCap);
+ netCap.setSSID(TEST_SSID);
+ assertEqualsThroughMarshalling(netCap);
}
@Test
@@ -362,6 +360,27 @@
}
@Test
+ public void testSSID() {
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+ assertTrue(nc2.satisfiedBySSID(nc1));
+
+ nc1.setSSID(TEST_SSID);
+ assertTrue(nc2.satisfiedBySSID(nc1));
+ nc2.setSSID("different " + TEST_SSID);
+ assertFalse(nc2.satisfiedBySSID(nc1));
+
+ assertTrue(nc1.satisfiedByImmutableNetworkCapabilities(nc2));
+ assertFalse(nc1.satisfiedByNetworkCapabilities(nc2));
+ }
+
+ private ArraySet<UidRange> uidRange(int from, int to) {
+ final ArraySet<UidRange> range = new ArraySet<>(1);
+ range.add(new UidRange(from, to));
+ return range;
+ }
+
+ @Test
public void testCombineCapabilities() {
NetworkCapabilities nc1 = new NetworkCapabilities();
NetworkCapabilities nc2 = new NetworkCapabilities();
@@ -382,6 +401,35 @@
// will never be satisfied.
assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ nc1.setSSID(TEST_SSID);
+ nc2.combineCapabilities(nc1);
+ assertTrue(TEST_SSID.equals(nc2.getSSID()));
+
+ // Because they now have the same SSID, the following call should not throw
+ nc2.combineCapabilities(nc1);
+
+ nc1.setSSID(DIFFERENT_TEST_SSID);
+ try {
+ nc2.combineCapabilities(nc1);
+ fail("Expected IllegalStateException: can't combine different SSIDs");
+ } catch (IllegalStateException expected) {}
+ nc1.setSSID(TEST_SSID);
+
+ nc1.setUids(uidRange(10, 13));
+ assertNotEquals(nc1, nc2);
+ nc2.combineCapabilities(nc1); // Everything + 10~13 is still everything.
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2); // 10~13 + everything is everything.
+ assertEquals(nc1, nc2);
+ nc1.setUids(uidRange(10, 13));
+ nc2.setUids(uidRange(20, 23));
+ assertNotEquals(nc1, nc2);
+ nc1.combineCapabilities(nc2);
+ assertTrue(nc1.appliesToUid(12));
+ assertFalse(nc2.appliesToUid(12));
+ assertTrue(nc1.appliesToUid(22));
+ assertTrue(nc2.appliesToUid(22));
}
@Test
@@ -420,4 +468,38 @@
p.setDataPosition(0);
assertEquals(NetworkCapabilities.CREATOR.createFromParcel(p), netCap);
}
+
+ @Test
+ public void testSet() {
+ NetworkCapabilities nc1 = new NetworkCapabilities();
+ NetworkCapabilities nc2 = new NetworkCapabilities();
+
+ nc1.addUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+ nc1.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ assertNotEquals(nc1, nc2);
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_CAPTIVE_PORTAL));
+
+ // This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
+ nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+ nc1.setSSID(TEST_SSID);
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+ // Contrary to combineCapabilities, set() will have removed the NOT_ROAMING capability
+ // from nc2.
+ assertFalse(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(TEST_SSID.equals(nc2.getSSID()));
+
+ nc1.setSSID(DIFFERENT_TEST_SSID);
+ nc2.set(nc1);
+ assertEquals(nc1, nc2);
+ assertTrue(DIFFERENT_TEST_SSID.equals(nc2.getSSID()));
+
+ nc1.setUids(uidRange(10, 13));
+ nc2.set(nc1); // Overwrites, as opposed to combineCapabilities
+ assertEquals(nc1, nc2);
+ }
}
diff --git a/tests/net/java/android/net/NetworkStatsHistoryTest.java b/tests/net/java/android/net/NetworkStatsHistoryTest.java
index 1c0c14e..301d04d 100644
--- a/tests/net/java/android/net/NetworkStatsHistoryTest.java
+++ b/tests/net/java/android/net/NetworkStatsHistoryTest.java
@@ -32,9 +32,14 @@
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.WEEK_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
@@ -46,25 +51,31 @@
import java.io.DataOutputStream;
import java.util.Random;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
@SmallTest
-public class NetworkStatsHistoryTest extends AndroidTestCase {
+public class NetworkStatsHistoryTest {
private static final String TAG = "NetworkStatsHistoryTest";
private static final long TEST_START = 1194220800000L;
private NetworkStatsHistory stats;
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
if (stats != null) {
assertConsistent(stats);
}
}
+ @Test
public void testReadOriginalVersion() throws Exception {
- final DataInputStream in = new DataInputStream(
- getContext().getResources().openRawResource(R.raw.history_v1));
+ final Context context = InstrumentationRegistry.getContext();
+ final DataInputStream in =
+ new DataInputStream(context.getResources().openRawResource(R.raw.history_v1));
NetworkStatsHistory.Entry entry = null;
try {
@@ -88,6 +99,7 @@
}
}
+ @Test
public void testRecordSingleBucket() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -100,6 +112,7 @@
assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L);
}
+ @Test
public void testRecordEqualBuckets() throws Exception {
final long bucketDuration = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(bucketDuration);
@@ -114,6 +127,7 @@
assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L);
}
+ @Test
public void testRecordTouchingBuckets() throws Exception {
final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -134,6 +148,7 @@
assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L);
}
+ @Test
public void testRecordGapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -165,6 +180,7 @@
assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L);
}
+ @Test
public void testRecordOverlapBuckets() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -182,6 +198,7 @@
assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L);
}
+ @Test
public void testRecordEntireGapIdentical() throws Exception {
// first, create two separate histories far apart
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
@@ -206,6 +223,7 @@
assertValues(stats, 3, 500L, 250L);
}
+ @Test
public void testRecordEntireOverlapVaryingBuckets() throws Exception {
// create history just over hour bucket boundary
final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS);
@@ -247,6 +265,7 @@
assertValues(stats, 3, 150L, 150L);
}
+ @Test
public void testRemove() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
@@ -280,6 +299,7 @@
assertEquals(0, stats.size());
}
+ @Test
public void testTotalData() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -304,7 +324,7 @@
}
- @Suppress
+ @Test
public void testFuzzing() throws Exception {
try {
// fuzzing with random events, looking for crashes
@@ -341,6 +361,7 @@
return value < 0 ? -value : value;
}
+ @Test
public void testIgnoreFields() throws Exception {
final NetworkStatsHistory history = new NetworkStatsHistory(
MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES);
@@ -353,6 +374,7 @@
assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN);
}
+ @Test
public void testIgnoreFieldsRecordIn() throws Exception {
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
final NetworkStatsHistory partial = new NetworkStatsHistory(
@@ -365,6 +387,7 @@
assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L);
}
+ @Test
public void testIgnoreFieldsRecordOut() throws Exception {
final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL);
final NetworkStatsHistory partial = new NetworkStatsHistory(
@@ -377,6 +400,7 @@
assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L);
}
+ @Test
public void testSerialize() throws Exception {
final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL);
before.recordData(0, 4 * MINUTE_IN_MILLIS,
@@ -396,6 +420,7 @@
assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L);
}
+ @Test
public void testVarLong() throws Exception {
assertEquals(0L, performVarLong(0L));
assertEquals(-1L, performVarLong(-1L));
@@ -409,6 +434,7 @@
assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40));
}
+ @Test
public void testIndexBeforeAfter() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -451,6 +477,7 @@
assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE);
}
+ @Test
public void testIntersects() throws Exception {
final long BUCKET_SIZE = HOUR_IN_MILLIS;
stats = new NetworkStatsHistory(BUCKET_SIZE);
@@ -485,6 +512,7 @@
assertTrue(stats.intersects(Long.MIN_VALUE, TEST_START + 1));
}
+ @Test
public void testSetValues() throws Exception {
stats = new NetworkStatsHistory(HOUR_IN_MILLIS);
stats.recordData(TEST_START, TEST_START + 1,
diff --git a/tests/net/java/android/net/NetworkUtilsTest.java b/tests/net/java/android/net/NetworkUtilsTest.java
index a5ee8e3..2b172da 100644
--- a/tests/net/java/android/net/NetworkUtilsTest.java
+++ b/tests/net/java/android/net/NetworkUtilsTest.java
@@ -16,17 +16,32 @@
package android.net;
-import android.net.NetworkUtils;
-import android.test.suitebuilder.annotation.SmallTest;
+import static android.net.NetworkUtils.getImplicitNetmask;
+import static android.net.NetworkUtils.inet4AddressToIntHTH;
+import static android.net.NetworkUtils.inet4AddressToIntHTL;
+import static android.net.NetworkUtils.intToInet4AddressHTH;
+import static android.net.NetworkUtils.intToInet4AddressHTL;
+import static android.net.NetworkUtils.netmaskToPrefixLength;
+import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTH;
+import static android.net.NetworkUtils.prefixLengthToV4NetmaskIntHTL;
+
+import static junit.framework.Assert.assertEquals;
+
+import static org.junit.Assert.fail;
+
+import android.support.test.runner.AndroidJUnit4;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.TreeSet;
-import junit.framework.TestCase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-public class NetworkUtilsTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@android.support.test.filters.SmallTest
+public class NetworkUtilsTest {
private InetAddress Address(String addr) {
return InetAddress.parseNumericAddress(addr);
@@ -36,41 +51,126 @@
return (Inet4Address) Address(addr);
}
- @SmallTest
+ @Test
public void testGetImplicitNetmask() {
- assertEquals(8, NetworkUtils.getImplicitNetmask(IPv4Address("4.2.2.2")));
- assertEquals(8, NetworkUtils.getImplicitNetmask(IPv4Address("10.5.6.7")));
- assertEquals(16, NetworkUtils.getImplicitNetmask(IPv4Address("173.194.72.105")));
- assertEquals(16, NetworkUtils.getImplicitNetmask(IPv4Address("172.23.68.145")));
- assertEquals(24, NetworkUtils.getImplicitNetmask(IPv4Address("192.0.2.1")));
- assertEquals(24, NetworkUtils.getImplicitNetmask(IPv4Address("192.168.5.1")));
- assertEquals(32, NetworkUtils.getImplicitNetmask(IPv4Address("224.0.0.1")));
- assertEquals(32, NetworkUtils.getImplicitNetmask(IPv4Address("255.6.7.8")));
+ assertEquals(8, getImplicitNetmask(IPv4Address("4.2.2.2")));
+ assertEquals(8, getImplicitNetmask(IPv4Address("10.5.6.7")));
+ assertEquals(16, getImplicitNetmask(IPv4Address("173.194.72.105")));
+ assertEquals(16, getImplicitNetmask(IPv4Address("172.23.68.145")));
+ assertEquals(24, getImplicitNetmask(IPv4Address("192.0.2.1")));
+ assertEquals(24, getImplicitNetmask(IPv4Address("192.168.5.1")));
+ assertEquals(32, getImplicitNetmask(IPv4Address("224.0.0.1")));
+ assertEquals(32, getImplicitNetmask(IPv4Address("255.6.7.8")));
}
private void assertInvalidNetworkMask(Inet4Address addr) {
try {
- NetworkUtils.netmaskToPrefixLength(addr);
+ netmaskToPrefixLength(addr);
fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
} catch (IllegalArgumentException expected) {
}
}
- @SmallTest
+ @Test
+ public void testInet4AddressToIntHTL() {
+ assertEquals(0, inet4AddressToIntHTL(IPv4Address("0.0.0.0")));
+ assertEquals(0x000080ff, inet4AddressToIntHTL(IPv4Address("255.128.0.0")));
+ assertEquals(0x0080ff0a, inet4AddressToIntHTL(IPv4Address("10.255.128.0")));
+ assertEquals(0x00feff0a, inet4AddressToIntHTL(IPv4Address("10.255.254.0")));
+ assertEquals(0xfeffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.254")));
+ assertEquals(0xffffa8c0, inet4AddressToIntHTL(IPv4Address("192.168.255.255")));
+ }
+
+ @Test
+ public void testIntToInet4AddressHTL() {
+ assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTL(0));
+ assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTL(0x000080ff));
+ assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTL(0x0080ff0a));
+ assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTL(0x00feff0a));
+ assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTL(0xfeffa8c0));
+ assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTL(0xffffa8c0));
+ }
+
+ @Test
+ public void testInet4AddressToIntHTH() {
+ assertEquals(0, inet4AddressToIntHTH(IPv4Address("0.0.0.0")));
+ assertEquals(0xff800000, inet4AddressToIntHTH(IPv4Address("255.128.0.0")));
+ assertEquals(0x0aff8000, inet4AddressToIntHTH(IPv4Address("10.255.128.0")));
+ assertEquals(0x0afffe00, inet4AddressToIntHTH(IPv4Address("10.255.254.0")));
+ assertEquals(0xc0a8fffe, inet4AddressToIntHTH(IPv4Address("192.168.255.254")));
+ assertEquals(0xc0a8ffff, inet4AddressToIntHTH(IPv4Address("192.168.255.255")));
+ }
+
+ @Test
+ public void testIntToInet4AddressHTH() {
+ assertEquals(IPv4Address("0.0.0.0"), intToInet4AddressHTH(0));
+ assertEquals(IPv4Address("255.128.0.0"), intToInet4AddressHTH(0xff800000));
+ assertEquals(IPv4Address("10.255.128.0"), intToInet4AddressHTH(0x0aff8000));
+ assertEquals(IPv4Address("10.255.254.0"), intToInet4AddressHTH(0x0afffe00));
+ assertEquals(IPv4Address("192.168.255.254"), intToInet4AddressHTH(0xc0a8fffe));
+ assertEquals(IPv4Address("192.168.255.255"), intToInet4AddressHTH(0xc0a8ffff));
+ }
+
+ @Test
public void testNetmaskToPrefixLength() {
- assertEquals(0, NetworkUtils.netmaskToPrefixLength(IPv4Address("0.0.0.0")));
- assertEquals(9, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.128.0.0")));
- assertEquals(17, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.128.0")));
- assertEquals(23, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.254.0")));
- assertEquals(31, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.255.254")));
- assertEquals(32, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.255.255")));
+ assertEquals(0, netmaskToPrefixLength(IPv4Address("0.0.0.0")));
+ assertEquals(9, netmaskToPrefixLength(IPv4Address("255.128.0.0")));
+ assertEquals(17, netmaskToPrefixLength(IPv4Address("255.255.128.0")));
+ assertEquals(23, netmaskToPrefixLength(IPv4Address("255.255.254.0")));
+ assertEquals(31, netmaskToPrefixLength(IPv4Address("255.255.255.254")));
+ assertEquals(32, netmaskToPrefixLength(IPv4Address("255.255.255.255")));
assertInvalidNetworkMask(IPv4Address("0.0.0.1"));
assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
}
- @SmallTest
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTL() {
+ assertEquals(0, prefixLengthToV4NetmaskIntHTL(0));
+ assertEquals(0x000080ff /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTL(9));
+ assertEquals(0x0080ffff /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTL(17));
+ assertEquals(0x00feffff /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTL(23));
+ assertEquals(0xfeffffff /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTL(31));
+ assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTL(32));
+ }
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTH() {
+ assertEquals(0, prefixLengthToV4NetmaskIntHTH(0));
+ assertEquals(0xff800000 /* 255.128.0.0 */, prefixLengthToV4NetmaskIntHTH(9));
+ assertEquals(0xffff8000 /* 255.255.128.0 */, prefixLengthToV4NetmaskIntHTH(17));
+ assertEquals(0xfffffe00 /* 255.255.254.0 */, prefixLengthToV4NetmaskIntHTH(23));
+ assertEquals(0xfffffffe /* 255.255.255.254 */, prefixLengthToV4NetmaskIntHTH(31));
+ assertEquals(0xffffffff /* 255.255.255.255 */, prefixLengthToV4NetmaskIntHTH(32));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPrefixLengthToV4NetmaskIntHTH_NegativeLength() {
+ prefixLengthToV4NetmaskIntHTH(-1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPrefixLengthToV4NetmaskIntHTH_LengthTooLarge() {
+ prefixLengthToV4NetmaskIntHTH(33);
+ }
+
+ private void checkAddressMasking(String expectedAddr, String addr, int prefixLength) {
+ final int prefix = prefixLengthToV4NetmaskIntHTH(prefixLength);
+ final int addrInt = inet4AddressToIntHTH(IPv4Address(addr));
+ assertEquals(IPv4Address(expectedAddr), intToInet4AddressHTH(prefix & addrInt));
+ }
+
+ @Test
+ public void testPrefixLengthToV4NetmaskIntHTH_MaskAddr() {
+ checkAddressMasking("192.168.0.0", "192.168.128.1", 16);
+ checkAddressMasking("255.240.0.0", "255.255.255.255", 12);
+ checkAddressMasking("255.255.255.255", "255.255.255.255", 32);
+ checkAddressMasking("0.0.0.0", "255.255.255.255", 0);
+ }
+
+ @Test
public void testRoutedIPv4AddressCount() {
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
// No routes routes to no addresses.
@@ -118,7 +218,7 @@
assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
}
- @SmallTest
+ @Test
public void testRoutedIPv6AddressCount() {
final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
// No routes routes to no addresses.
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
index fc46b9c..788924b 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
@@ -116,20 +116,6 @@
}
@Test
- public void testNetworkStatsSummary() throws Exception {
- stageFile(R.raw.net_dev_typical, file("net/dev"));
-
- final NetworkStats stats = mFactory.readNetworkStatsIfaceDev();
- assertEquals(6, stats.size());
- assertStatsEntry(stats, "lo", UID_ALL, SET_ALL, TAG_NONE, 8308L, 8308L);
- assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 1507570L, 489339L);
- assertStatsEntry(stats, "ifb0", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
- assertStatsEntry(stats, "ifb1", UID_ALL, SET_ALL, TAG_NONE, 52454L, 0L);
- assertStatsEntry(stats, "sit0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
- assertStatsEntry(stats, "ip6tnl0", UID_ALL, SET_ALL, TAG_NONE, 0L, 0L);
- }
-
- @Test
public void testNetworkStatsSingle() throws Exception {
stageFile(R.raw.xt_qtaguid_iface_typical, file("net/xt_qtaguid/iface_stat_all"));
diff --git a/tests/net/java/com/android/internal/util/RingBufferTest.java b/tests/net/java/com/android/internal/util/RingBufferTest.java
index 7a23443..90a373a 100644
--- a/tests/net/java/com/android/internal/util/RingBufferTest.java
+++ b/tests/net/java/com/android/internal/util/RingBufferTest.java
@@ -17,6 +17,7 @@
package com.android.internal.util;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import android.support.test.filters.SmallTest;
@@ -129,6 +130,55 @@
assertArraysEqual(expected2, buffer.toArray());
}
+ @Test
+ public void testGetNextSlot() {
+ int capacity = 100;
+ RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
+
+ final DummyClass1[] actual = new DummyClass1[capacity];
+ final DummyClass1[] expected = new DummyClass1[capacity];
+ for (int i = 0; i < capacity; ++i) {
+ final DummyClass1 obj = buffer.getNextSlot();
+ obj.x = capacity * i;
+ actual[i] = obj;
+ expected[i] = new DummyClass1();
+ expected[i].x = capacity * i;
+ }
+ assertArraysEqual(expected, buffer.toArray());
+
+ for (int i = 0; i < capacity; ++i) {
+ if (actual[i] != buffer.getNextSlot()) {
+ fail("getNextSlot() should re-use objects if available");
+ }
+ }
+
+ RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
+ assertNull("getNextSlot() should return null if the object can't be initiated "
+ + "(No nullary constructor)", buffer2.getNextSlot());
+
+ RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
+ assertNull("getNextSlot() should return null if the object can't be initiated "
+ + "(Inaccessible class)", buffer3.getNextSlot());
+ }
+
+ public static final class DummyClass1 {
+ int x;
+
+ public boolean equals(Object o) {
+ if (o instanceof DummyClass1) {
+ final DummyClass1 other = (DummyClass1) o;
+ return other.x == this.x;
+ }
+ return false;
+ }
+ }
+
+ public static final class DummyClass2 {
+ public DummyClass2(int x) {}
+ }
+
+ private static final class DummyClass3 {}
+
static <T> void assertArraysEqual(T[] expected, T[] got) {
if (expected.length != got.length) {
fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index d04160e..e3db7e8 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -57,13 +57,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.eq;
@@ -94,6 +93,7 @@
import android.net.ConnectivityThread;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
+import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -111,6 +111,7 @@
import android.net.RouteInfo;
import android.net.StringNetworkSpecifier;
import android.net.UidRange;
+import android.net.captiveportal.CaptivePortalProbeResult;
import android.net.metrics.IpConnectivityLog;
import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
@@ -122,6 +123,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
@@ -132,6 +134,7 @@
import android.util.ArraySet;
import android.util.Log;
+import com.android.internal.net.VpnConfig;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -141,6 +144,7 @@
import com.android.server.connectivity.DnsManager;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
+import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.Vpn;
@@ -157,10 +161,14 @@
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -183,8 +191,18 @@
private static final String TAG = "ConnectivityServiceTest";
private static final int TIMEOUT_MS = 500;
- private static final int TEST_LINGER_DELAY_MS = 120;
+ private static final int TEST_LINGER_DELAY_MS = 250;
+ // Chosen to be less than the linger timeout. This ensures that we can distinguish between a
+ // LOST callback that arrives immediately and a LOST callback that arrives after the linger
+ // timeout. For this, our assertions should run fast enough to leave less than
+ // (mService.mLingerDelayMs - TEST_CALLBACK_TIMEOUT_MS) between the time callbacks are
+ // supposedly fired, and the time we call expectCallback.
+ private final static int TEST_CALLBACK_TIMEOUT_MS = 200;
+ // Chosen to be less than TEST_CALLBACK_TIMEOUT_MS. This ensures that requests have time to
+ // complete before callbacks are verified.
+ private final static int TEST_REQUEST_TIMEOUT_MS = 150;
+ private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
@@ -194,6 +212,7 @@
private MockNetworkAgent mWiFiNetworkAgent;
private MockNetworkAgent mCellNetworkAgent;
private MockNetworkAgent mEthernetNetworkAgent;
+ private MockVpn mMockVpn;
private Context mContext;
@Mock IpConnectivityMetrics.Logger mMetricsService;
@@ -475,6 +494,14 @@
mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
}
+ public void setNetworkCapabilities(NetworkCapabilities nc,
+ boolean sendToConnectivityService) {
+ mNetworkCapabilities.set(nc);
+ if (sendToConnectivityService) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
public void connectWithoutInternet() {
mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -504,6 +531,7 @@
mWrappedNetworkMonitor.gen204ProbeResult = 204;
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+ .clearCapabilities()
.build();
callback = new NetworkCallback() {
public void onCapabilitiesChanged(Network network,
@@ -589,6 +617,10 @@
return mRedirectUrl;
}
+ public NetworkAgent getNetworkAgent() {
+ return mNetworkAgent;
+ }
+
public NetworkCapabilities getNetworkCapabilities() {
return mNetworkCapabilities;
}
@@ -721,6 +753,87 @@
}
}
+ private static Looper startHandlerThreadAndReturnLooper() {
+ final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
+ handlerThread.start();
+ return handlerThread.getLooper();
+ }
+
+ private class MockVpn extends Vpn {
+ // TODO : the interactions between this mock and the mock network agent are too
+ // hard to get right at this moment, because it's unclear in which case which
+ // target needs to get a method call or both, and in what order. It's because
+ // MockNetworkAgent wants to manage its own NetworkCapabilities, but the Vpn
+ // parent class of MockVpn agent wants that responsibility.
+ // That being said inside the test it should be possible to make the interactions
+ // harder to get wrong with precise speccing, judicious comments, helper methods
+ // and a few sprinkled assertions.
+
+ private boolean mConnected = false;
+ // Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
+ // not inherit from NetworkAgent.
+ private MockNetworkAgent mMockNetworkAgent;
+
+ public MockVpn(int userId) {
+ super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
+ userId);
+ }
+
+ public void setNetworkAgent(MockNetworkAgent agent) {
+ waitForIdle(agent, TIMEOUT_MS);
+ mMockNetworkAgent = agent;
+ mNetworkAgent = agent.getNetworkAgent();
+ mNetworkCapabilities.set(agent.getNetworkCapabilities());
+ }
+
+ public void setUids(Set<UidRange> uids) {
+ mNetworkCapabilities.setUids(uids);
+ updateCapabilities();
+ }
+
+ @Override
+ public int getNetId() {
+ return mMockNetworkAgent.getNetwork().netId;
+ }
+
+ @Override
+ public boolean appliesToUid(int uid) {
+ return mConnected; // Trickery to simplify testing.
+ }
+
+ @Override
+ protected boolean isCallerEstablishedOwnerLocked() {
+ return mConnected; // Similar trickery
+ }
+
+ public void connect() {
+ mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
+ mConnected = true;
+ mConfig = new VpnConfig();
+ }
+
+ @Override
+ public void updateCapabilities() {
+ if (!mConnected) return;
+ super.updateCapabilities();
+ // Because super.updateCapabilities will update the capabilities of the agent but not
+ // the mock agent, the mock agent needs to know about them.
+ copyCapabilitiesToNetworkAgent();
+ }
+
+ private void copyCapabilitiesToNetworkAgent() {
+ if (null != mMockNetworkAgent) {
+ mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
+ false /* sendToConnectivityService */);
+ }
+ }
+
+ public void disconnect() {
+ mConnected = false;
+ mConfig = null;
+ }
+ }
+
private class FakeWakeupMessage extends WakeupMessage {
private static final int UNREASONABLY_LONG_WAIT = 1000;
@@ -767,7 +880,7 @@
NetworkAgentInfo networkAgentInfo, NetworkRequest defaultRequest,
IpConnectivityLog log) {
super(context, handler, networkAgentInfo, defaultRequest, log,
- NetworkMonitor.NetworkMonitorSettings.DEFAULT);
+ NetworkMonitor.Dependencies.DEFAULT);
connectivityHandler = handler;
}
@@ -850,6 +963,10 @@
return monitor;
}
+ public Nat464Xlat getNat464Xlat(MockNetworkAgent mna) {
+ return getNetworkAgentInfoForNetwork(mna.getNetwork()).clatd;
+ }
+
@Override
public MultinetworkPolicyTracker createMultinetworkPolicyTracker(
Context c, Handler h, Runnable r) {
@@ -879,10 +996,25 @@
return mMetricsService;
}
+ @Override
+ protected void registerNetdEventCallback() {
+ }
+
public WrappedNetworkMonitor getLastCreatedWrappedNetworkMonitor() {
return mLastCreatedNetworkMonitor;
}
+ public void mockVpn(int uid) {
+ synchronized (mVpns) {
+ int userId = UserHandle.getUserId(uid);
+ mMockVpn = new MockVpn(userId);
+ // This has no effect unless the VPN is actually connected, because things like
+ // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+ // netId, and check if that network is actually connected.
+ mVpns.put(userId, mMockVpn);
+ }
+ }
+
public void waitForIdle(int timeoutMs) {
waitForIdleHandler(mHandlerThread, timeoutMs);
}
@@ -926,8 +1058,11 @@
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
- mService.systemReady();
+ // Create local CM before sending system ready so that we can answer
+ // getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
+ mService.systemReady();
+ mService.mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
// Ensure that the default setting for Captive Portals is used for most tests
@@ -1334,12 +1469,8 @@
* received. assertNoCallback may be called at any time.
*/
private class TestNetworkCallback extends NetworkCallback {
- // Chosen to be much less than the linger timeout. This ensures that we can distinguish
- // between a LOST callback that arrives immediately and a LOST callback that arrives after
- // the linger timeout.
- private final static int TIMEOUT_MS = 100;
-
private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
+ private Network mLastAvailableNetwork;
protected void setLastCallback(CallbackState state, Network network, Object o) {
mCallbacks.offer(new CallbackInfo(state, network, o));
@@ -1347,6 +1478,7 @@
@Override
public void onAvailable(Network network) {
+ mLastAvailableNetwork = network;
setLastCallback(CallbackState.AVAILABLE, network, null);
}
@@ -1382,9 +1514,14 @@
@Override
public void onLost(Network network) {
+ mLastAvailableNetwork = null;
setLastCallback(CallbackState.LOST, network, null);
}
+ public Network getLastAvailableNetwork() {
+ return mLastAvailableNetwork;
+ }
+
CallbackInfo nextCallback(int timeoutMs) {
CallbackInfo cb = null;
try {
@@ -1407,20 +1544,20 @@
if (state == CallbackState.LOSING) {
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
- actual.arg, 0, TEST_LINGER_DELAY_MS);
+ actual.arg, 0, mService.mLingerDelayMs);
int maxMsToLive = (Integer) actual.arg;
- assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
+ assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= mService.mLingerDelayMs);
}
return actual;
}
CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
- return expectCallback(state, agent, TIMEOUT_MS);
+ return expectCallback(state, agent, TEST_CALLBACK_TIMEOUT_MS);
}
CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn) {
- return expectCallbackLike(fn, TIMEOUT_MS);
+ return expectCallbackLike(fn, TEST_CALLBACK_TIMEOUT_MS);
}
CallbackInfo expectCallbackLike(Predicate<CallbackInfo> fn, int timeoutMs) {
@@ -1463,15 +1600,15 @@
// Expects the available callbacks (validated), plus onSuspended.
void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent, boolean expectValidated) {
- expectAvailableCallbacks(agent, true, expectValidated, TIMEOUT_MS);
+ expectAvailableCallbacks(agent, true, expectValidated, TEST_CALLBACK_TIMEOUT_MS);
}
void expectAvailableCallbacksValidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, true, TIMEOUT_MS);
+ expectAvailableCallbacks(agent, false, true, TEST_CALLBACK_TIMEOUT_MS);
}
void expectAvailableCallbacksUnvalidated(MockNetworkAgent agent) {
- expectAvailableCallbacks(agent, false, false, TIMEOUT_MS);
+ expectAvailableCallbacks(agent, false, false, TEST_CALLBACK_TIMEOUT_MS);
}
// Expects the available callbacks (where the onCapabilitiesChanged must contain the
@@ -1479,9 +1616,9 @@
// one we just sent.
// TODO: this is likely a bug. Fix it and remove this method.
void expectAvailableDoubleValidatedCallbacks(MockNetworkAgent agent) {
- expectCallback(CallbackState.AVAILABLE, agent, TIMEOUT_MS);
+ expectCallback(CallbackState.AVAILABLE, agent, TEST_CALLBACK_TIMEOUT_MS);
NetworkCapabilities nc1 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
- expectCallback(CallbackState.LINK_PROPERTIES, agent, TIMEOUT_MS);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, TEST_CALLBACK_TIMEOUT_MS);
NetworkCapabilities nc2 = expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
assertEquals(nc1, nc2);
}
@@ -1495,7 +1632,7 @@
}
NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
- return expectCapabilitiesWith(capability, agent, TIMEOUT_MS);
+ return expectCapabilitiesWith(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
}
NetworkCapabilities expectCapabilitiesWith(int capability, MockNetworkAgent agent,
@@ -1507,7 +1644,7 @@
}
NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
- return expectCapabilitiesWithout(capability, agent, TIMEOUT_MS);
+ return expectCapabilitiesWithout(capability, agent, TEST_CALLBACK_TIMEOUT_MS);
}
NetworkCapabilities expectCapabilitiesWithout(int capability, MockNetworkAgent agent,
@@ -1520,7 +1657,8 @@
void expectCapabilitiesLike(Predicate<NetworkCapabilities> fn, MockNetworkAgent agent) {
CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
- assertTrue(fn.test((NetworkCapabilities) cbi.arg));
+ assertTrue("Received capabilities don't match expectations : " + cbi.arg,
+ fn.test((NetworkCapabilities) cbi.arg));
}
void assertNoCallback() {
@@ -1630,6 +1768,12 @@
@Test
public void testMultipleLingering() {
+ // 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
+ // lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
+ // in detecting races.
+ mService.mLingerDelayMs = 300;
+
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
.build();
@@ -1651,6 +1795,7 @@
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
@@ -1661,6 +1806,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
@@ -1669,11 +1815,13 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1702,6 +1850,7 @@
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
@@ -1711,8 +1860,11 @@
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(callback);
waitForIdle();
@@ -1729,6 +1881,7 @@
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
@@ -1737,12 +1890,14 @@
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
// Cell is lingered because it would not satisfy any request, even if it validated.
@@ -1753,6 +1908,7 @@
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
@@ -1760,6 +1916,7 @@
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
@@ -1771,6 +1928,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -1779,12 +1937,15 @@
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -1792,6 +1953,7 @@
// TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1808,6 +1970,7 @@
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1818,6 +1981,7 @@
mWiFiNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1827,7 +1991,7 @@
// Let linger run its course.
callback.assertNoCallback();
- final int lingerTimeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
+ final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent, lingerTimeoutMs);
// Register a TRACK_DEFAULT request and check that it does not affect lingering.
@@ -1841,6 +2005,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Let linger run its course.
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
@@ -2489,23 +2654,27 @@
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down wifi. Expect the default network callback to notified of LOST wifi
// followed by AVAILABLE cell.
@@ -2516,6 +2685,24 @@
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
+
+ final int uid = Process.myUid();
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(true);
+ mMockVpn.connect();
+ defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
}
@Test
@@ -3028,12 +3215,12 @@
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int timeoutMs = 150;
- mCm.requestNetwork(nr, networkCallback, timeoutMs);
+ mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, timeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false,
+ TEST_CALLBACK_TIMEOUT_MS);
// pass timeout and validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -3048,13 +3235,12 @@
NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
NetworkCapabilities.TRANSPORT_WIFI).build();
final TestNetworkCallback networkCallback = new TestNetworkCallback();
- final int requestTimeoutMs = 50;
- mCm.requestNetwork(nr, networkCallback, requestTimeoutMs);
+ mCm.requestNetwork(nr, networkCallback, TEST_REQUEST_TIMEOUT_MS);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- final int assertTimeoutMs = 100;
- networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false, assertTimeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, false,
+ TEST_CALLBACK_TIMEOUT_MS);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -3433,8 +3619,10 @@
@Test
public void testNetworkCallbackMaximum() {
- final int MAX_REQUESTS = 100;
- final int CALLBACKS = 90;
+ // We can only have 99 callbacks, because MultipathPolicyTracker is
+ // already one of them.
+ final int MAX_REQUESTS = 99;
+ final int CALLBACKS = 89;
final int INTENTS = 10;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
@@ -3773,6 +3961,11 @@
// The default on Android is opportunistic mode ("Automatic").
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.requestNetwork(cellRequest, cellNetworkCallback);
+
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
waitForIdle();
// CS tells netd about the empty DNS config for this network.
@@ -3808,6 +4001,14 @@
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
reset(mNetworkManagementService);
+ cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ mCellNetworkAgent);
+ CallbackInfo cbi = cellNetworkCallback.expectCallback(
+ CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
@@ -3817,6 +4018,7 @@
assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
reset(mNetworkManagementService);
+ cellNetworkCallback.assertNoCallback();
setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
@@ -3829,8 +4031,112 @@
assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
new String[]{"2001:db8::1", "192.0.2.1"}));
reset(mNetworkManagementService);
+ cellNetworkCallback.assertNoCallback();
- // Can't test strict mode without properly mocking out the DNS lookups.
+ setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
+ // Can't test dns configuration for strict mode without properly mocking
+ // out the DNS lookups, but can test that LinkProperties is updated.
+ cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertEquals("strict.example.com", ((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ }
+
+ @Test
+ public void testLinkPropertiesWithPrivateDnsValidationEvents() throws Exception {
+ // The default on Android is opportunistic mode ("Automatic").
+ setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
+
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.requestNetwork(cellRequest, cellNetworkCallback);
+
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ waitForIdle();
+ LinkProperties lp = new LinkProperties();
+ mCellNetworkAgent.sendLinkProperties(lp);
+ mCellNetworkAgent.connect(false);
+ waitForIdle();
+ cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
+ mCellNetworkAgent);
+ CallbackInfo cbi = cellNetworkCallback.expectCallback(
+ CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ Set<InetAddress> dnsServers = new HashSet<>();
+ checkDnsServers(cbi.arg, dnsServers);
+
+ // Send a validation event for a server that is not part of the current
+ // resolver config. The validation event should be ignored.
+ mService.mNetdEventCallback.onPrivateDnsValidationEvent(
+ mCellNetworkAgent.getNetwork().netId, "", "145.100.185.18", true);
+ cellNetworkCallback.assertNoCallback();
+
+ // Add a dns server to the LinkProperties.
+ LinkProperties lp2 = new LinkProperties(lp);
+ lp2.addDnsServer(InetAddress.getByName("145.100.185.16"));
+ mCellNetworkAgent.sendLinkProperties(lp2);
+ cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ dnsServers.add(InetAddress.getByName("145.100.185.16"));
+ checkDnsServers(cbi.arg, dnsServers);
+
+ // Send a validation event containing a hostname that is not part of
+ // the current resolver config. The validation event should be ignored.
+ mService.mNetdEventCallback.onPrivateDnsValidationEvent(
+ mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "hostname", true);
+ cellNetworkCallback.assertNoCallback();
+
+ // Send a validation event where validation failed.
+ mService.mNetdEventCallback.onPrivateDnsValidationEvent(
+ mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", false);
+ cellNetworkCallback.assertNoCallback();
+
+ // Send a validation event where validation succeeded for a server in
+ // the current resolver config. A LinkProperties callback with updated
+ // private dns fields should be sent.
+ mService.mNetdEventCallback.onPrivateDnsValidationEvent(
+ mCellNetworkAgent.getNetwork().netId, "145.100.185.16", "", true);
+ cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ checkDnsServers(cbi.arg, dnsServers);
+
+ // The private dns fields in LinkProperties should be preserved when
+ // the network agent sends unrelated changes.
+ LinkProperties lp3 = new LinkProperties(lp2);
+ lp3.setMtu(1300);
+ mCellNetworkAgent.sendLinkProperties(lp3);
+ cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertTrue(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ checkDnsServers(cbi.arg, dnsServers);
+ assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
+
+ // Removing the only validated server should affect the private dns
+ // fields in LinkProperties.
+ LinkProperties lp4 = new LinkProperties(lp3);
+ lp4.removeDnsServer(InetAddress.getByName("145.100.185.16"));
+ mCellNetworkAgent.sendLinkProperties(lp4);
+ cbi = cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES,
+ mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+ assertFalse(((LinkProperties)cbi.arg).isPrivateDnsActive());
+ assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
+ dnsServers.remove(InetAddress.getByName("145.100.185.16"));
+ checkDnsServers(cbi.arg, dnsServers);
+ assertEquals(1300, ((LinkProperties)cbi.arg).getMtu());
}
private void checkDirectlyConnectedRoutes(Object callbackObj,
@@ -3850,6 +4156,13 @@
assertTrue(observedRoutes.containsAll(expectedRoutes));
}
+ private static void checkDnsServers(Object callbackObj, Set<InetAddress> dnsServers) {
+ assertTrue(callbackObj instanceof LinkProperties);
+ LinkProperties lp = (LinkProperties) callbackObj;
+ assertEquals(dnsServers.size(), lp.getDnsServers().size());
+ assertTrue(lp.getDnsServers().containsAll(dnsServers));
+ }
+
private static <T> void assertEmpty(T[] ts) {
int length = ts.length;
assertEquals("expected empty array, but length was " + length, 0, length);
@@ -3881,6 +4194,7 @@
final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
final NetworkRequest genericRequest = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN).build();
@@ -3893,6 +4207,8 @@
mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ defaultCallback.assertNoCallback();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
@@ -3900,26 +4216,30 @@
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ defaultCallback.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.
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
- vpnNetworkAgent.setUids(ranges);
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
vpnNetworkAgent.connect(false);
+ mMockVpn.connect();
genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
vpnNetworkAgent.setUids(ranges);
@@ -3929,13 +4249,24 @@
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ // TODO : The default network callback should actually get a LOST call here (also see the
+ // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
+ // ranges at all when determining whether a network should be rematched. In practice, VPNs
+ // can't currently update their UIDs without disconnecting, so this does not matter too
+ // much, but that is the reason the test here has to check for an update to the
+ // capabilities instead of the expected LOST then AVAILABLE.
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+
ranges.add(new UidRange(uid, uid));
- vpnNetworkAgent.setUids(ranges);
+ mMockVpn.setUids(ranges);
genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
+ // happen outside of the test, ConnectivityService does not rematch callbacks.
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
@@ -3943,6 +4274,7 @@
genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
+ defaultCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
@@ -3950,9 +4282,254 @@
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
mCm.unregisterNetworkCallback(wifiNetworkCallback);
mCm.unregisterNetworkCallback(vpnNetworkCallback);
+ mCm.unregisterNetworkCallback(defaultCallback);
+ }
+
+ @Test
+ public void testVpnWithAndWithoutInternet() {
+ final int uid = Process.myUid();
+
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ defaultCallback.assertNoCallback();
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+
+ defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+ mMockVpn.connect();
+
+ defaultCallback.assertNoCallback();
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultCallback.assertNoCallback();
+
+ vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
+ mMockVpn.connect();
+ defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+
+ vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ ranges.clear();
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+ mMockVpn.connect();
+ defaultCallback.assertNoCallback();
+
+ mCm.unregisterNetworkCallback(defaultCallback);
+ }
+
+ @Test
+ public void testVpnSetUnderlyingNetworks() {
+ final int uid = Process.myUid();
+
+ final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .addTransportType(TRANSPORT_VPN)
+ .build();
+ NetworkCapabilities nc;
+ mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+ vpnNetworkCallback.assertNoCallback();
+
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.connect();
+ mMockVpn.setUids(ranges);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+
+ vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ assertTrue(nc.hasTransport(TRANSPORT_VPN));
+ assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(nc.hasTransport(TRANSPORT_WIFI));
+ // For safety reasons a VPN without underlying networks is considered metered.
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+
+ // Connect cell and use it as an underlying network.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ mService.setUnderlyingNetworksForVpn(
+ new Network[] { mCellNetworkAgent.getNetwork() });
+
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
+ mWiFiNetworkAgent.connect(true);
+
+ mService.setUnderlyingNetworksForVpn(
+ new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
+
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ // Don't disconnect, but note the VPN is not using wifi any more.
+ mService.setUnderlyingNetworksForVpn(
+ new Network[] { mCellNetworkAgent.getNetwork() });
+
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ // Use Wifi but not cell. Note the VPN is now unmetered.
+ mService.setUnderlyingNetworksForVpn(
+ new Network[] { mWiFiNetworkAgent.getNetwork() });
+
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ // Use both again.
+ mService.setUnderlyingNetworksForVpn(
+ new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
+
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ // Disconnect cell. Receive update without even removing the dead network from the
+ // underlying networks – it's dead anyway. Not metered any more.
+ mCellNetworkAgent.disconnect();
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
+ && caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ // Disconnect wifi too. No underlying networks means this is now metered.
+ mWiFiNetworkAgent.disconnect();
+ vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
+ && !caps.hasCapability(NET_CAPABILITY_NOT_METERED),
+ vpnNetworkAgent);
+
+ mMockVpn.disconnect();
+ }
+
+ /**
+ * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
+ */
+ private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
+ InterfaceConfiguration cfg = new InterfaceConfiguration();
+ cfg.setHardwareAddress("11:22:33:44:55:66");
+ cfg.setLinkAddress(la);
+ return cfg;
+ }
+
+ /**
+ * Make expected stack link properties, copied from Nat464Xlat.
+ */
+ private LinkProperties makeClatLinkProperties(LinkAddress la) {
+ LinkAddress clatAddress = la;
+ LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName(CLAT_PREFIX + MOBILE_IFNAME);
+ RouteInfo ipv4Default = new RouteInfo(
+ new LinkAddress(Inet4Address.ANY, 0),
+ clatAddress.getAddress(), CLAT_PREFIX + MOBILE_IFNAME);
+ stacked.addRoute(ipv4Default);
+ stacked.addLinkAddress(clatAddress);
+ return stacked;
+ }
+
+ @Test
+ public void testStackedLinkProperties() throws UnknownHostException, RemoteException {
+ final LinkAddress myIpv4 = new LinkAddress("1.2.3.4/24");
+ final LinkAddress myIpv6 = new LinkAddress("2001:db8:1::1/64");
+ final NetworkRequest networkRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .build();
+ final TestNetworkCallback networkCallback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(networkRequest, networkCallback);
+
+ // Prepare ipv6 only link properties and connect.
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ final LinkProperties cellLp = new LinkProperties();
+ cellLp.setInterfaceName(MOBILE_IFNAME);
+ cellLp.addLinkAddress(myIpv6);
+ cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
+ cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
+ reset(mNetworkManagementService);
+ when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfig(myIpv4));
+
+ // Connect with ipv6 link properties, then expect clat setup ipv4 and update link
+ // properties properly.
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ mCellNetworkAgent.connect(true);
+ networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).startClatd(MOBILE_IFNAME);
+ Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
+
+ // Clat iface up, expect stack link updated.
+ clat.interfaceLinkStateChanged(CLAT_PREFIX + MOBILE_IFNAME, true);
+ waitForIdle();
+ List<LinkProperties> stackedLps = mCm.getLinkProperties(mCellNetworkAgent.getNetwork())
+ .getStackedLinks();
+ assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
+
+ // Change trivial linkproperties and see if stacked link is preserved.
+ cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+
+ List<LinkProperties> stackedLpsAfterChange =
+ mCm.getLinkProperties(mCellNetworkAgent.getNetwork()).getStackedLinks();
+ assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
+ assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
+
+ // Add ipv4 address, expect stacked linkproperties be cleaned up
+ cellLp.addLinkAddress(myIpv4);
+ cellLp.addRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
+ mCellNetworkAgent.sendLinkProperties(cellLp);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ verify(mNetworkManagementService, times(1)).stopClatd(MOBILE_IFNAME);
+
+ // Clat iface removed, expect linkproperties revert to original one
+ clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
+ waitForIdle();
+ networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
+ LinkProperties actualLpAfterIpv4 = mCm.getLinkProperties(mCellNetworkAgent.getNetwork());
+ assertEquals(cellLp, actualLpAfterIpv4);
+
+ // Clean up
+ mCellNetworkAgent.disconnect();
+ mCm.unregisterNetworkCallback(networkCallback);
}
}
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 410f754..102cb7c 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -27,6 +27,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.AppOpsManager;
import android.content.Context;
import android.net.INetd;
import android.net.IpSecAlgorithm;
@@ -40,6 +41,7 @@
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
+import android.test.mock.MockContext;
import android.support.test.filters.SmallTest;
import android.system.Os;
@@ -48,6 +50,7 @@
import java.util.Collection;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -92,7 +95,28 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
};
- Context mMockContext;
+ AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+
+ MockContext mMockContext = new MockContext() {
+ @Override
+ public Object getSystemService(String name) {
+ switch(name) {
+ case Context.APP_OPS_SERVICE:
+ return mMockAppOps;
+ default:
+ return null;
+ }
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
+ return;
+ }
+ throw new SecurityException("Unavailable permission requested");
+ }
+ };
+
INetd mMockNetd;
IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
IpSecService mIpSecService;
@@ -114,13 +138,22 @@
@Before
public void setUp() throws Exception {
- mMockContext = mock(Context.class);
mMockNetd = mock(INetd.class);
mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
// Injecting mock netd
when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
+ // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
+ // A system package will not be granted the app op, so this should fall back to
+ // a permissions check, which should pass.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
+ .thenReturn(AppOpsManager.MODE_DEFAULT);
+ // A mismatch between the package name and the UID will return MODE_IGNORED.
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
}
@Test
@@ -232,7 +265,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -267,7 +300,7 @@
ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verify(mMockNetd)
@@ -301,12 +334,12 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
// Attempting to create transform a second time with the same SPIs should throw an error...
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -314,7 +347,7 @@
// ... even if the transform is deleted
mIpSecService.deleteTransform(createTransformResp.resourceId);
try {
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -327,7 +360,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -351,7 +384,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
mIpSecService.deleteTransform(createTransformResp.resourceId);
verify(mMockNetd, times(1))
@@ -398,7 +431,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -435,7 +468,7 @@
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder());
+ mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
int resourceId = createTransformResp.resourceId;
@@ -460,10 +493,10 @@
}
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
- String localAddr, String remoteAddr) {
+ String localAddr, String remoteAddr, String pkgName) {
IpSecTunnelInterfaceResponse createTunnelResp =
mIpSecService.createTunnelInterface(
- mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());
+ mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
assertNotNull(createTunnelResp);
assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
@@ -473,7 +506,7 @@
@Test
public void testCreateTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
// Check that we have stored the tracking object, and retrieve it
IpSecService.UserRecord userRecord =
@@ -495,12 +528,12 @@
@Test
public void testDeleteTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -516,7 +549,7 @@
@Test
public void testTunnelInterfaceBinderDeath() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
IpSecService.UserRecord userRecord =
mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
@@ -539,22 +572,35 @@
@Test
public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr);
+ for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
+ mIpSecService.addAddressToTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceAddAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.removeAddressFromTunnelInterface(
+ createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
+ verify(mMockNetd, times(1))
+ .interfaceDelAddress(
+ eq(createTunnelResp.interfaceName),
+ eq(mLocalInnerAddress.getAddress().getHostAddress()),
+ eq(mLocalInnerAddress.getPrefixLength()));
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
+ }
+ }
- mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceAddAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
-
- mIpSecService.removeAddressFromTunnelInterface(
- createTunnelResp.resourceId, mLocalInnerAddress);
- verify(mMockNetd)
- .interfaceDelAddress(
- eq(createTunnelResp.interfaceName),
- eq(mLocalInnerAddress.getAddress().getHostAddress()),
- eq(mLocalInnerAddress.getPrefixLength()));
+ @Ignore
+ @Test
+ public void testAddTunnelFailsForBadPackageName() throws Exception {
+ try {
+ IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+ fail("Expected a SecurityException for badPackage.");
+ } catch (SecurityException expected) {
+ }
}
}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
new file mode 100644
index 0000000..01b468a
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -0,0 +1,263 @@
+/*
+ * 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;
+
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
+import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.RouteInfo;
+import android.os.INetworkManagementService;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.mock.MockContentResolver;
+
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.DnsManager.PrivateDnsConfig;
+import com.android.server.connectivity.MockableSystemProperties;
+
+import java.net.InetAddress;
+import java.util.Arrays;
+
+import org.junit.runner.RunWith;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link DnsManager}.
+ *
+ * Build, install and run with:
+ * runtest frameworks-net -c com.android.server.connectivity.DnsManagerTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DnsManagerTest {
+ static final String TEST_IFACENAME = "test_wlan0";
+ static final int TEST_NETID = 100;
+ static final int TEST_NETID_ALTERNATE = 101;
+ static final int TEST_NETID_UNTRACKED = 102;
+ final boolean IS_DEFAULT = true;
+ final boolean NOT_DEFAULT = false;
+
+ DnsManager mDnsManager;
+ MockContentResolver mContentResolver;
+
+ @Mock Context mCtx;
+ @Mock INetworkManagementService mNMService;
+ @Mock MockableSystemProperties mSystemProperties;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mContentResolver = new MockContentResolver();
+ mContentResolver.addProvider(Settings.AUTHORITY,
+ new FakeSettingsProvider());
+ when(mCtx.getContentResolver()).thenReturn(mContentResolver);
+ mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
+
+ // Clear the private DNS settings
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, "");
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "");
+ }
+
+ @Test
+ public void testTrackedValidationUpdates() throws Exception {
+ mDnsManager.updatePrivateDns(new Network(TEST_NETID),
+ mDnsManager.getPrivateDnsConfig());
+ mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
+ mDnsManager.getPrivateDnsConfig());
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(TEST_IFACENAME);
+ lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
+ lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
+
+ // Send a validation event that is tracked on the alternate netId
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID_ALTERNATE, lp, NOT_DEFAULT);
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE,
+ InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+ LinkProperties fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertFalse(fixedLp.isPrivateDnsActive());
+ assertNull(fixedLp.getPrivateDnsServerName());
+ fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
+ assertTrue(fixedLp.isPrivateDnsActive());
+ assertNull(fixedLp.getPrivateDnsServerName());
+ assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
+ fixedLp.getValidatedPrivateDnsServers());
+
+ // Set up addresses for strict mode and switch to it.
+ lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
+ lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
+ TEST_IFACENAME));
+ lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
+ lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
+ TEST_IFACENAME));
+
+ Settings.Global.putString(mContentResolver,
+ PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ mDnsManager.updatePrivateDns(new Network(TEST_NETID),
+ new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
+ InetAddress.parseNumericAddress("6.6.6.6"),
+ InetAddress.parseNumericAddress("2001:db8:66:66::1")
+ }));
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
+ fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertTrue(fixedLp.isPrivateDnsActive());
+ assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
+ // No validation events yet.
+ assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
+ // Validate one.
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
+ fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
+ fixedLp.getValidatedPrivateDnsServers());
+ // Validate the 2nd one.
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+ fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertEquals(Arrays.asList(
+ InetAddress.parseNumericAddress("2001:db8:66:66::1"),
+ InetAddress.parseNumericAddress("6.6.6.6")),
+ fixedLp.getValidatedPrivateDnsServers());
+ }
+
+ @Test
+ public void testIgnoreUntrackedValidationUpdates() throws Exception {
+ // The PrivateDnsConfig map is empty, so no validation events will
+ // be tracked.
+ LinkProperties lp = new LinkProperties();
+ lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Validation event has untracked netId
+ mDnsManager.updatePrivateDns(new Network(TEST_NETID),
+ mDnsManager.getPrivateDnsConfig());
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
+ InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Validation event has untracked ipAddress
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("4.4.4.4"), "", true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Validation event has untracked hostname
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("3.3.3.3"), "hostname",
+ true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Validation event failed
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("3.3.3.3"), "", false));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Network removed
+ mDnsManager.removeNetwork(new Network(TEST_NETID));
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+
+ // Turn private DNS mode off
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF);
+ mDnsManager.updatePrivateDns(new Network(TEST_NETID),
+ mDnsManager.getPrivateDnsConfig());
+ mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("3.3.3.3"), "", true));
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, lp);
+ assertFalse(lp.isPrivateDnsActive());
+ assertNull(lp.getPrivateDnsServerName());
+ }
+
+ @Test
+ public void testOverrideDefaultMode() throws Exception {
+ // Hard-coded default is opportunistic mode.
+ final PrivateDnsConfig cfgAuto = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertTrue(cfgAuto.useTls);
+ assertEquals("", cfgAuto.hostname);
+ assertEquals(new InetAddress[0], cfgAuto.ips);
+
+ // Pretend a gservices push sets the default to "off".
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "off");
+ final PrivateDnsConfig cfgOff = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertFalse(cfgOff.useTls);
+ assertEquals("", cfgOff.hostname);
+ assertEquals(new InetAddress[0], cfgOff.ips);
+
+ // Strict mode still works.
+ Settings.Global.putString(
+ mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ Settings.Global.putString(mContentResolver, PRIVATE_DNS_SPECIFIER, "strictmode.com");
+ final PrivateDnsConfig cfgStrict = DnsManager.getPrivateDnsConfig(mContentResolver);
+ assertTrue(cfgStrict.useTls);
+ assertEquals("strictmode.com", cfgStrict.hostname);
+ assertEquals(new InetAddress[0], cfgStrict.ips);
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
new file mode 100644
index 0000000..e58811b
--- /dev/null
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -0,0 +1,360 @@
+/*
+ * 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;
+
+import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkPolicy.LIMIT_DISABLED;
+import static android.net.NetworkPolicy.SNOOZE_NEVER;
+import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES;
+
+import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH;
+import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.usage.NetworkStatsManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
+import android.net.NetworkTemplate;
+import android.net.StringNetworkSpecifier;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+import android.test.mock.MockContentResolver;
+import android.util.DataUnit;
+import android.util.RecurrenceRule;
+
+import com.android.internal.R;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.LocalServices;
+import com.android.server.net.NetworkPolicyManagerInternal;
+import com.android.server.net.NetworkStatsManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Clock;
+import java.time.Instant;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MultipathPolicyTrackerTest {
+ private static final Network TEST_NETWORK = new Network(123);
+ private static final int POLICY_SNOOZED = -100;
+
+ @Mock private Context mContext;
+ @Mock private Resources mResources;
+ @Mock private Handler mHandler;
+ @Mock private MultipathPolicyTracker.Dependencies mDeps;
+ @Mock private Clock mClock;
+ @Mock private ConnectivityManager mCM;
+ @Mock private NetworkPolicyManager mNPM;
+ @Mock private NetworkStatsManager mStatsManager;
+ @Mock private NetworkPolicyManagerInternal mNPMI;
+ @Mock private NetworkStatsManagerInternal mNetworkStatsManagerInternal;
+ @Mock private TelephonyManager mTelephonyManager;
+ private MockContentResolver mContentResolver;
+
+ private ArgumentCaptor<BroadcastReceiver> mConfigChangeReceiverCaptor;
+
+ private MultipathPolicyTracker mTracker;
+
+ private Clock mPreviousRecurrenceRuleClock;
+ private boolean mRecurrenceRuleClockMocked;
+
+ private <T> void mockService(String serviceName, Class<T> serviceClass, T service) {
+ when(mContext.getSystemServiceName(serviceClass)).thenReturn(serviceName);
+ when(mContext.getSystemService(serviceName)).thenReturn(service);
+ }
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mPreviousRecurrenceRuleClock = RecurrenceRule.sClock;
+ RecurrenceRule.sClock = mClock;
+ mRecurrenceRuleClockMocked = true;
+
+ mConfigChangeReceiverCaptor = ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ when(mContext.registerReceiverAsUser(mConfigChangeReceiverCaptor.capture(),
+ any(), argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
+ .thenReturn(null);
+
+ when(mDeps.getClock()).thenReturn(mClock);
+
+ when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mTelephonyManager);
+
+ mContentResolver = Mockito.spy(new MockContentResolver(mContext));
+ mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ Settings.Global.clearProviderForTest();
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+
+ mockService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class, mCM);
+ mockService(Context.NETWORK_POLICY_SERVICE, NetworkPolicyManager.class, mNPM);
+ mockService(Context.NETWORK_STATS_SERVICE, NetworkStatsManager.class, mStatsManager);
+ mockService(Context.TELEPHONY_SERVICE, TelephonyManager.class, mTelephonyManager);
+
+ LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
+ LocalServices.addService(NetworkPolicyManagerInternal.class, mNPMI);
+
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
+ LocalServices.addService(NetworkStatsManagerInternal.class, mNetworkStatsManagerInternal);
+
+ mTracker = new MultipathPolicyTracker(mContext, mHandler, mDeps);
+ }
+
+ @After
+ public void tearDown() {
+ // Avoid setting static clock to null (which should normally not be the case)
+ // if MockitoAnnotations.initMocks threw an exception
+ if (mRecurrenceRuleClockMocked) {
+ RecurrenceRule.sClock = mPreviousRecurrenceRuleClock;
+ }
+ mRecurrenceRuleClockMocked = false;
+ }
+
+ private void setDefaultQuotaGlobalSetting(long setting) {
+ Settings.Global.putInt(mContentResolver, NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES,
+ (int) setting);
+ }
+
+ private void testGetMultipathPreference(
+ long usedBytesToday, long subscriptionQuota, long policyWarning, long policyLimit,
+ long defaultGlobalSetting, long defaultResSetting, boolean roaming) {
+
+ // TODO: tests should not use ZoneId.systemDefault() once code handles TZ correctly.
+ final ZonedDateTime now = ZonedDateTime.ofInstant(
+ Instant.parse("2017-04-02T10:11:12Z"), ZoneId.systemDefault());
+ final ZonedDateTime startOfDay = now.truncatedTo(ChronoUnit.DAYS);
+ when(mClock.millis()).thenReturn(now.toInstant().toEpochMilli());
+ when(mClock.instant()).thenReturn(now.toInstant());
+ when(mClock.getZone()).thenReturn(ZoneId.systemDefault());
+
+ // Setup plan quota
+ when(mNPMI.getSubscriptionOpportunisticQuota(TEST_NETWORK, QUOTA_TYPE_MULTIPATH))
+ .thenReturn(subscriptionQuota);
+
+ // Setup user policy warning / limit
+ if (policyWarning != WARNING_DISABLED || policyLimit != LIMIT_DISABLED) {
+ final Instant recurrenceStart = Instant.parse("2017-04-01T00:00:00Z");
+ final RecurrenceRule recurrenceRule = new RecurrenceRule(
+ ZonedDateTime.ofInstant(
+ recurrenceStart,
+ ZoneId.systemDefault()),
+ null /* end */,
+ Period.ofMonths(1));
+ final boolean snoozeWarning = policyWarning == POLICY_SNOOZED;
+ final boolean snoozeLimit = policyLimit == POLICY_SNOOZED;
+ when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[] {
+ new NetworkPolicy(
+ NetworkTemplate.buildTemplateMobileWildcard(),
+ recurrenceRule,
+ snoozeWarning ? 0 : policyWarning,
+ snoozeLimit ? 0 : policyLimit,
+ snoozeWarning ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
+ snoozeLimit ? recurrenceStart.toEpochMilli() + 1 : SNOOZE_NEVER,
+ SNOOZE_NEVER,
+ true /* metered */,
+ false /* inferred */)
+ });
+ } else {
+ when(mNPM.getNetworkPolicies()).thenReturn(new NetworkPolicy[0]);
+ }
+
+ // Setup default quota in settings and resources
+ if (defaultGlobalSetting > 0) {
+ setDefaultQuotaGlobalSetting(defaultGlobalSetting);
+ }
+ when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
+ .thenReturn((int) defaultResSetting);
+
+ when(mNetworkStatsManagerInternal.getNetworkTotalBytes(
+ any(),
+ eq(startOfDay.toInstant().toEpochMilli()),
+ eq(now.toInstant().toEpochMilli()))).thenReturn(usedBytesToday);
+
+ ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ mTracker.start();
+ verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any());
+
+ // Simulate callback after capability changes
+ final NetworkCapabilities capabilities = new NetworkCapabilities()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new StringNetworkSpecifier("234"));
+ if (!roaming) {
+ capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ networkCallback.getValue().onCapabilitiesChanged(
+ TEST_NETWORK,
+ capabilities);
+ }
+
+ @Test
+ public void testGetMultipathPreference_SubscriptionQuota() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
+ DataUnit.MEGABYTES.toBytes(14) /* subscriptionQuota */,
+ DataUnit.MEGABYTES.toBytes(100) /* policyWarning */,
+ LIMIT_DISABLED,
+ DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
+ 2_500_000 /* defaultResSetting */,
+ false /* roaming */);
+
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
+ }
+
+ @Test
+ public void testGetMultipathPreference_UserWarningQuota() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
+ OPPORTUNISTIC_QUOTA_UNKNOWN,
+ // 29 days from Apr. 2nd to May 1st
+ DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyWarning */,
+ LIMIT_DISABLED,
+ DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
+ 2_500_000 /* defaultResSetting */,
+ false /* roaming */);
+
+ // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
+ }
+
+ @Test
+ public void testGetMultipathPreference_SnoozedWarningQuota() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
+ OPPORTUNISTIC_QUOTA_UNKNOWN,
+ // 29 days from Apr. 2nd to May 1st
+ POLICY_SNOOZED /* policyWarning */,
+ DataUnit.MEGABYTES.toBytes(15 * 29 * 20) /* policyLimit */,
+ DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
+ 2_500_000 /* defaultResSetting */,
+ false /* roaming */);
+
+ // Daily budget should be 15MB (5% of daily quota), 7MB used today: callback set for 8MB
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
+ }
+
+ @Test
+ public void testGetMultipathPreference_SnoozedBothQuota() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(7) /* usedBytesToday */,
+ OPPORTUNISTIC_QUOTA_UNKNOWN,
+ // 29 days from Apr. 2nd to May 1st
+ POLICY_SNOOZED /* policyWarning */,
+ POLICY_SNOOZED /* policyLimit */,
+ DataUnit.MEGABYTES.toBytes(12) /* defaultGlobalSetting */,
+ 2_500_000 /* defaultResSetting */,
+ false /* roaming */);
+
+ // Default global setting should be used: 12 - 7 = 5
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(5)), any(), any());
+ }
+
+ @Test
+ public void testGetMultipathPreference_SettingChanged() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
+ OPPORTUNISTIC_QUOTA_UNKNOWN,
+ WARNING_DISABLED,
+ LIMIT_DISABLED,
+ -1 /* defaultGlobalSetting */,
+ DataUnit.MEGABYTES.toBytes(10) /* defaultResSetting */,
+ false /* roaming */);
+
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(8)), any(), any());
+
+ // Update setting
+ setDefaultQuotaGlobalSetting(DataUnit.MEGABYTES.toBytes(14));
+ mTracker.mSettingsObserver.onChange(
+ false, Settings.Global.getUriFor(NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES));
+
+ // Callback must have been re-registered with new setting
+ verify(mStatsManager, times(1)).unregisterUsageCallback(any());
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
+ }
+
+ @Test
+ public void testGetMultipathPreference_ResourceChanged() {
+ testGetMultipathPreference(
+ DataUnit.MEGABYTES.toBytes(2) /* usedBytesToday */,
+ OPPORTUNISTIC_QUOTA_UNKNOWN,
+ WARNING_DISABLED,
+ LIMIT_DISABLED,
+ -1 /* defaultGlobalSetting */,
+ DataUnit.MEGABYTES.toBytes(14) /* defaultResSetting */,
+ false /* roaming */);
+
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(12)), any(), any());
+
+ when(mResources.getInteger(R.integer.config_networkDefaultDailyMultipathQuotaBytes))
+ .thenReturn((int) DataUnit.MEGABYTES.toBytes(16));
+
+ final BroadcastReceiver configChangeReceiver = mConfigChangeReceiverCaptor.getValue();
+ assertNotNull(configChangeReceiver);
+ configChangeReceiver.onReceive(mContext, new Intent());
+
+ // Uses the new setting (16 - 2 = 14MB)
+ verify(mStatsManager, times(1)).registerUsageCallback(
+ any(), anyInt(), eq(DataUnit.MEGABYTES.toBytes(14)), any(), any());
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 4a83d1b..f025f41 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -26,6 +26,8 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -62,8 +64,8 @@
private void expectPermission(String[] permissions, boolean preinstalled) throws Exception {
final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled);
- when(mPackageManager.getPackageInfo(MOCK_PACKAGE_NAMES[0], GET_PERMISSIONS))
- .thenReturn(packageInfo);
+ when(mPackageManager.getPackageInfoAsUser(
+ eq(MOCK_PACKAGE_NAMES[0]), eq(GET_PERMISSIONS), anyInt())).thenReturn(packageInfo);
}
private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index 23318c2..b870bbd 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -176,7 +176,7 @@
}
private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
- when(mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
+ when(mAppOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, TEST_UID, TEST_PKG))
.thenReturn(appOpsMode);
when(mContext.checkCallingPermission(Manifest.permission.PACKAGE_USAGE_STATS)).thenReturn(
hasPermission ? PackageManager.PERMISSION_GRANTED
diff --git a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
index da0a48a..6f14332 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsCollectionTest.java
@@ -26,6 +26,9 @@
import static android.os.Process.myUid;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
import static com.android.server.net.NetworkStatsCollection.multiplySafe;
@@ -37,11 +40,12 @@
import android.net.NetworkTemplate;
import android.os.Process;
import android.os.UserHandle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.telephony.SubscriptionPlan;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.DateUtils;
import android.util.RecurrenceRule;
@@ -64,11 +68,17 @@
import java.util.ArrayList;
import java.util.List;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
/**
* Tests for {@link NetworkStatsCollection}.
*/
+@RunWith(AndroidJUnit4.class)
@SmallTest
-public class NetworkStatsCollectionTest extends AndroidTestCase {
+public class NetworkStatsCollectionTest {
private static final String TEST_FILE = "test.bin";
private static final String TEST_IMSI = "310260000000000";
@@ -79,18 +89,15 @@
private static Clock sOriginalClock;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
sOriginalClock = RecurrenceRule.sClock;
-
// ignore any device overlay while testing
NetworkTemplate.forceAllNetworkTypes();
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
RecurrenceRule.sClock = sOriginalClock;
}
@@ -98,8 +105,10 @@
RecurrenceRule.sClock = Clock.fixed(instant, ZoneId.systemDefault());
}
+ @Test
public void testReadLegacyNetwork() throws Exception {
- final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ final File testFile =
+ new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_v1, testFile);
final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -124,8 +133,10 @@
636016770L, 709306L, 88038768L, 518836L, NetworkStatsAccess.Level.DEVICE);
}
+ @Test
public void testReadLegacyUid() throws Exception {
- final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ final File testFile =
+ new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_uid_v4, testFile);
final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -150,8 +161,10 @@
637076152L, 711413L, 88343717L, 521022L, NetworkStatsAccess.Level.DEVICE);
}
+ @Test
public void testReadLegacyUidTags() throws Exception {
- final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ final File testFile =
+ new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_uid_v4, testFile);
final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -176,6 +189,7 @@
77017831L, 100995L, 35436758L, 92344L);
}
+ @Test
public void testStartEndAtomicBuckets() throws Exception {
final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
@@ -190,6 +204,7 @@
assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis());
}
+ @Test
public void testAccessLevels() throws Exception {
final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS);
final NetworkStats.Entry entry = new NetworkStats.Entry();
@@ -250,8 +265,10 @@
0, NetworkStatsAccess.Level.DEVICE);
}
+ @Test
public void testAugmentPlan() throws Exception {
- final File testFile = new File(getContext().getFilesDir(), TEST_FILE);
+ final File testFile =
+ new File(InstrumentationRegistry.getContext().getFilesDir(), TEST_FILE);
stageFile(R.raw.netstats_v1, testFile);
final NetworkStatsCollection emptyCollection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS);
@@ -439,6 +456,7 @@
}
}
+ @Test
public void testAugmentPlanGigantic() throws Exception {
// We're in the future, but not that far off
setClock(Instant.parse("2012-06-01T00:00:00.00Z"));
@@ -461,6 +479,7 @@
assertEquals(4_939_212_386L, getHistory(large, plan, TIME_A, TIME_C).getTotalBytes());
}
+ @Test
public void testRounding() throws Exception {
final NetworkStatsCollection coll = new NetworkStatsCollection(HOUR_IN_MILLIS);
@@ -482,6 +501,7 @@
assertEquals(TIME_A - HOUR_IN_MILLIS, coll.roundDown(TIME_A - 1));
}
+ @Test
public void testMultiplySafe() {
assertEquals(25, multiplySafe(50, 1, 2));
assertEquals(100, multiplySafe(50, 2, 1));
@@ -510,7 +530,7 @@
InputStream in = null;
OutputStream out = null;
try {
- in = getContext().getResources().openRawResource(rawId);
+ in = InstrumentationRegistry.getContext().getResources().openRawResource(rawId);
out = new FileOutputStream(file);
Streams.copy(in, out);
} finally {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 17ca651..280e4c2 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -91,16 +91,16 @@
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
+import android.os.SimpleClock;
import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-import android.util.TrustedTime;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.test.BroadcastInterceptingContext;
+import com.android.server.LocalServices;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings;
import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config;
@@ -116,6 +116,8 @@
import org.mockito.MockitoAnnotations;
import java.io.File;
+import java.time.Clock;
+import java.time.ZoneOffset;
import java.util.Objects;
/**
@@ -160,7 +162,6 @@
private File mStatsDir;
private @Mock INetworkManagementService mNetManager;
- private @Mock TrustedTime mTime;
private @Mock NetworkStatsSettings mSettings;
private @Mock IConnectivityManager mConnManager;
private @Mock IBinder mBinder;
@@ -172,6 +173,13 @@
private INetworkStatsSession mSession;
private INetworkManagementEventObserver mNetworkObserver;
+ private final Clock mClock = new SimpleClock(ZoneOffset.UTC) {
+ @Override
+ public long millis() {
+ return currentTimeMillis();
+ }
+ };
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -189,7 +197,7 @@
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, wakeLock, mTime,
+ mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
TelephonyManager.getDefault(), mSettings, new NetworkStatsObservers(),
mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new HandlerThread("HandlerThread");
@@ -201,7 +209,6 @@
mElapsedRealtime = 0L;
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -216,18 +223,19 @@
ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
-
}
@After
public void tearDown() throws Exception {
+ // Registered by NetworkStatsService's constructor.
+ LocalServices.removeServiceForTest(NetworkStatsManagerInternal.class);
+
IoUtils.deleteContents(mStatsDir);
mServiceContext = null;
mStatsDir = null;
mNetManager = null;
- mTime = null;
mSettings = null;
mConnManager = null;
@@ -239,7 +247,6 @@
public void testNetworkStatsWifi() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -254,7 +261,6 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
@@ -268,7 +274,6 @@
// and bump forward again, with counters going higher. this is
// important, since polling should correctly subtract last snapshot.
incrementCurrentTime(DAY_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L));
@@ -286,7 +291,6 @@
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -301,7 +305,6 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L));
@@ -330,13 +333,11 @@
// graceful shutdown system, which should trigger persist of stats, and
// clear any values in memory.
- expectCurrentTime();
expectDefaultSettings();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN));
assertStatsFilesExist(true);
// boot through serviceReady() again
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsUidDetail(buildEmptyStats());
expectSystemReady();
@@ -364,7 +365,6 @@
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -376,7 +376,6 @@
// modify some number on wifi, and trigger poll event
incrementCurrentTime(2 * HOUR_IN_MILLIS);
- expectCurrentTime();
expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L));
@@ -392,7 +391,6 @@
// now change bucket duration setting and trigger another poll with
// exact same values, which should resize existing buckets.
- expectCurrentTime();
expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS);
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -409,7 +407,6 @@
@Test
public void testUidStatsAcrossNetworks() throws Exception {
// pretend first mobile network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -421,7 +418,6 @@
// create some traffic on first network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L));
@@ -443,7 +439,6 @@
// now switch networks; this also tests that we're okay with interfaces
// disappearing, to verify we don't count backwards.
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_2));
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
@@ -460,7 +455,6 @@
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L));
@@ -489,7 +483,6 @@
@Test
public void testUidRemovedIsMoved() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -501,7 +494,6 @@
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
@@ -523,7 +515,6 @@
// now pretend two UIDs are uninstalled, which should migrate stats to
// special "removed" bucket.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L));
@@ -551,7 +542,6 @@
@Test
public void testUid3g4gCombinedByTemplate() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -563,7 +553,6 @@
// create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -579,7 +568,6 @@
// now switch over to 4g network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile4gState(TEST_IFACE2));
expectNetworkStatsSummary(buildEmptyStats());
@@ -594,7 +582,6 @@
// create traffic on second network
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -613,7 +600,6 @@
@Test
public void testSummaryForAllUid() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -625,7 +611,6 @@
// create some traffic for two apps
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -643,7 +628,6 @@
// now create more traffic in next hour, but only for one app
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -763,7 +747,6 @@
@Test
public void testForegroundBackground() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -775,7 +758,6 @@
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -791,7 +773,6 @@
// now switch to foreground
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1)
@@ -824,7 +805,6 @@
@Test
public void testMetered() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState(true /* isMetered */));
expectNetworkStatsSummary(buildEmptyStats());
@@ -836,7 +816,6 @@
// create some initial traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO, ROAMING_NO
@@ -866,7 +845,6 @@
@Test
public void testRoaming() throws Exception {
// pretend that network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */));
expectNetworkStatsSummary(buildEmptyStats());
@@ -878,7 +856,6 @@
// Create some traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
// Note that all traffic from NetworkManagementService is tagged as METERED_NO and
@@ -907,7 +884,6 @@
@Test
public void testTethering() throws Exception {
// pretend first mobile network comes online
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildMobile3gState(IMSI_1));
expectNetworkStatsSummary(buildEmptyStats());
@@ -919,7 +895,6 @@
// create some tethering traffic
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
// Traffic seen by kernel counters (includes software tethering).
@@ -952,7 +927,6 @@
public void testRegisterUsageCallback() throws Exception {
// pretend that wifi network comes online; service should ask about full
// network state, and poll any existing interfaces before updating.
- expectCurrentTime();
expectDefaultSettings();
expectNetworkState(buildWifiState());
expectNetworkStatsSummary(buildEmptyStats());
@@ -963,7 +937,6 @@
// verify service has empty history for wifi
assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0);
- String callingPackage = "the.calling.package";
long thresholdInBytes = 1L; // very small; should be overriden by framework
DataUsageRequest inputRequest = new DataUsageRequest(
DataUsageRequest.REQUEST_ID_UNSET, sTemplateWifi, thresholdInBytes);
@@ -974,7 +947,6 @@
Messenger messenger = new Messenger(latchedHandler);
// Force poll
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -983,7 +955,7 @@
// Register and verify request and that binder was called
DataUsageRequest request =
- mService.registerUsageCallback(callingPackage, inputRequest,
+ mService.registerUsageCallback(mServiceContext.getOpPackageName(), inputRequest,
messenger, mBinder);
assertTrue(request.requestId > 0);
assertTrue(Objects.equals(sTemplateWifi, request.template));
@@ -1003,7 +975,6 @@
// modify some number on wifi, and trigger poll event
// not enough traffic to call data usage callback
incrementCurrentTime(HOUR_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L));
@@ -1019,7 +990,6 @@
// and bump forward again, with counters going higher. this is
// important, since it will trigger the data usage callback
incrementCurrentTime(DAY_IN_MILLIS);
- expectCurrentTime();
expectDefaultSettings();
expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1)
.addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L));
@@ -1162,7 +1132,6 @@
private void expectSettings(long persistBytes, long bucketDuration, long deleteAge)
throws Exception {
when(mSettings.getPollInterval()).thenReturn(HOUR_IN_MILLIS);
- when(mSettings.getTimeCacheMaxAge()).thenReturn(DAY_IN_MILLIS);
when(mSettings.getSampleEnabled()).thenReturn(true);
final Config config = new Config(bucketDuration, deleteAge, deleteAge);
@@ -1178,14 +1147,6 @@
when(mSettings.getUidTagPersistBytes(anyLong())).thenReturn(MB_IN_BYTES);
}
- private void expectCurrentTime() throws Exception {
- when(mTime.forceRefresh()).thenReturn(false);
- when(mTime.hasCache()).thenReturn(true);
- when(mTime.currentTimeMillis()).thenReturn(currentTimeMillis());
- when(mTime.getCacheAge()).thenReturn(0L);
- when(mTime.getCacheCertainty()).thenReturn(0L);
- }
-
private void expectBandwidthControlCheck() throws Exception {
when(mNetManager.isBandwidthControlEnabled()).thenReturn(true);
}