Fix several HTTP proxy issues with multinetworking.
1. Send PROXY_CHANGE_ACTION broadcast when any network's proxy changes,
not just the default network.
2. When a process is bound to a particular Network, update the proxy
system properties to those for the bound Network, and keep them
updated when PROXY_CHANGE_ACTION broadcasts are received.
3. Make Network.openConnection() use the proxy for the Network.
bug:17905627
bug:17420465
bug:18144582
(cherry-pick of https://android-review.googlesource.com/#/c/115170)
Change-Id: Ia2819985e6108a8c121e74c683a5646becfd0a97
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6b4db10..bcd8fb4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -44,7 +44,10 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.hardware.display.DisplayManagerGlobal;
+import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
+import android.net.LinkProperties;
+import android.net.Network;
import android.net.Proxy;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -839,7 +842,13 @@
}
public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
- Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
+ final Network network = ConnectivityManager.getProcessDefaultNetwork();
+ if (network != null) {
+ Proxy.setHttpProxySystemProperty(
+ ConnectivityManager.from(getSystemContext()).getDefaultProxy());
+ } else {
+ Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
+ }
}
public void processInBackground() {
@@ -4430,7 +4439,7 @@
// crash if we can't get it.
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
- ProxyInfo proxyInfo = service.getProxy();
+ final ProxyInfo proxyInfo = service.getDefaultProxy();
Proxy.setHttpProxySystemProperty(proxyInfo);
} catch (RemoteException e) {}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4215f20..e0f6b8f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -452,6 +452,13 @@
public static final int NETID_UNSET = 0;
private final IConnectivityManager mService;
+ /**
+ * A kludge to facilitate static access where a Context pointer isn't available, like in the
+ * case of the static set/getProcessDefaultNetwork methods and from the Network class.
+ * TODO: Remove this after deprecating the static methods in favor of non-static methods or
+ * methods that take a Context argument.
+ */
+ private static ConnectivityManager sInstance;
private INetworkManagementService mNMService;
@@ -1397,6 +1404,7 @@
*/
public ConnectivityManager(IConnectivityManager service) {
mService = checkNotNull(service, "missing IConnectivityManager");
+ sInstance = this;
}
/** {@hide} */
@@ -1419,6 +1427,18 @@
}
/**
+ * @deprecated - use getSystemService. This is a kludge to support static access in certain
+ * situations where a Context pointer is unavailable.
+ * @hide
+ */
+ public static ConnectivityManager getInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("No ConnectivityManager yet constructed");
+ }
+ return sInstance;
+ }
+
+ /**
* Get the set of tetherable, available interfaces. This list is limited by
* device configuration and current interface existence.
*
@@ -1749,20 +1769,26 @@
}
/**
- * Get the HTTP proxy settings for the current default network. Note that
- * if a global proxy is set, it will override any per-network setting.
+ * Get the current default HTTP proxy settings. If a global proxy is set it will be returned,
+ * otherwise if this process is bound to a {@link Network} using
+ * {@link #setProcessDefaultNetwork} then that {@code Network}'s proxy is returned, otherwise
+ * the default network's proxy is returned.
*
* @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
* HTTP proxy is active.
- *
- * <p>This method requires the call to hold the permission
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
- * {@hide}
- * @deprecated Deprecated in favor of {@link #getLinkProperties}
+ * @hide
*/
- public ProxyInfo getProxy() {
+ public ProxyInfo getDefaultProxy() {
+ final Network network = getProcessDefaultNetwork();
+ if (network != null) {
+ final ProxyInfo globalProxy = getGlobalProxy();
+ if (globalProxy != null) return globalProxy;
+ final LinkProperties lp = getLinkProperties(network);
+ if (lp != null) return lp.getHttpProxy();
+ return null;
+ }
try {
- return mService.getProxy();
+ return mService.getDefaultProxy();
} catch (RemoteException e) {
return null;
}
@@ -2475,6 +2501,9 @@
return true;
}
if (NetworkUtils.bindProcessToNetwork(netId)) {
+ // Set HTTP proxy system properties to match network.
+ // TODO: Deprecate this static method and replace it with a non-static version.
+ Proxy.setHttpProxySystemProperty(getInstance().getDefaultProxy());
// Must flush DNS cache as new network may have different DNS resolutions.
InetAddress.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d9921a6..46af112 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -100,7 +100,7 @@
void setGlobalProxy(in ProxyInfo p);
- ProxyInfo getProxy();
+ ProxyInfo getDefaultProxy();
void setDataDependency(int networkType, boolean met);
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 4fa0593..5c12696 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -27,6 +27,7 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
+import java.net.ProxySelector;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
@@ -244,16 +245,46 @@
* @see java.net.URL#openConnection()
*/
public URLConnection openConnection(URL url) throws IOException {
+ final ConnectivityManager cm = ConnectivityManager.getInstance();
+ // TODO: Should this be optimized to avoid fetching the global proxy for every request?
+ ProxyInfo proxyInfo = cm.getGlobalProxy();
+ if (proxyInfo == null) {
+ // TODO: Should this be optimized to avoid fetching LinkProperties for every request?
+ final LinkProperties lp = cm.getLinkProperties(this);
+ if (lp != null) proxyInfo = lp.getHttpProxy();
+ }
+ java.net.Proxy proxy = null;
+ if (proxyInfo != null) {
+ proxy = proxyInfo.makeProxy();
+ } else {
+ proxy = java.net.Proxy.NO_PROXY;
+ }
+ return openConnection(url, proxy);
+ }
+
+ /**
+ * Opens the specified {@link URL} on this {@code Network}, such that all traffic will be sent
+ * on this Network. The URL protocol must be {@code HTTP} or {@code HTTPS}.
+ *
+ * @param proxy the proxy through which the connection will be established.
+ * @return a {@code URLConnection} to the resource referred to by this URL.
+ * @throws MalformedURLException if the URL protocol is not HTTP or HTTPS.
+ * @throws IllegalArgumentException if the argument proxy is null.
+ * @throws IOException if an error occurs while opening the connection.
+ * @see java.net.URL#openConnection()
+ * @hide
+ */
+ public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException {
+ if (proxy == null) throw new IllegalArgumentException("proxy is null");
maybeInitHttpClient();
String protocol = url.getProtocol();
OkHttpClient client;
// TODO: HttpHandler creates OkHttpClients that share the default ResponseCache.
// Could this cause unexpected behavior?
- // TODO: Should the network's proxy be specified?
if (protocol.equals("http")) {
- client = HttpHandler.createHttpOkHttpClient(null /* proxy */);
+ client = HttpHandler.createHttpOkHttpClient(proxy);
} else if (protocol.equals("https")) {
- client = HttpsHandler.createHttpsOkHttpClient(null /* proxy */);
+ client = HttpsHandler.createHttpsOkHttpClient(proxy);
} else {
// OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
// passed another protocol.
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 7694420..a3cad77 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -260,7 +260,8 @@
if (!Uri.EMPTY.equals(mPacFileUrl)) {
sb.append("PAC Script: ");
sb.append(mPacFileUrl);
- } else if (mHost != null) {
+ }
+ if (mHost != null) {
sb.append("[");
sb.append(mHost);
sb.append("] ");