Merge "Fix several HTTP proxy issues with multinetworking." into lmp-mr1-dev
This commit is contained in:
@@ -44,7 +44,10 @@ import android.database.sqlite.SQLiteDebug.DbStats;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.hardware.display.DisplayManagerGlobal;
|
import android.hardware.display.DisplayManagerGlobal;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
import android.net.IConnectivityManager;
|
import android.net.IConnectivityManager;
|
||||||
|
import android.net.LinkProperties;
|
||||||
|
import android.net.Network;
|
||||||
import android.net.Proxy;
|
import android.net.Proxy;
|
||||||
import android.net.ProxyInfo;
|
import android.net.ProxyInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
@@ -839,8 +842,14 @@ public final class ActivityThread {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
|
public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
|
||||||
|
final Network network = ConnectivityManager.getProcessDefaultNetwork();
|
||||||
|
if (network != null) {
|
||||||
|
Proxy.setHttpProxySystemProperty(
|
||||||
|
ConnectivityManager.from(getSystemContext()).getDefaultProxy());
|
||||||
|
} else {
|
||||||
Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
|
Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void processInBackground() {
|
public void processInBackground() {
|
||||||
mH.removeMessages(H.GC_WHEN_IDLE);
|
mH.removeMessages(H.GC_WHEN_IDLE);
|
||||||
@@ -4430,7 +4439,7 @@ public final class ActivityThread {
|
|||||||
// crash if we can't get it.
|
// crash if we can't get it.
|
||||||
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
|
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
|
||||||
try {
|
try {
|
||||||
ProxyInfo proxyInfo = service.getProxy();
|
final ProxyInfo proxyInfo = service.getDefaultProxy();
|
||||||
Proxy.setHttpProxySystemProperty(proxyInfo);
|
Proxy.setHttpProxySystemProperty(proxyInfo);
|
||||||
} catch (RemoteException e) {}
|
} catch (RemoteException e) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,6 +441,13 @@ public class ConnectivityManager {
|
|||||||
public static final int NETID_UNSET = 0;
|
public static final int NETID_UNSET = 0;
|
||||||
|
|
||||||
private final IConnectivityManager mService;
|
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;
|
private INetworkManagementService mNMService;
|
||||||
|
|
||||||
@@ -1392,6 +1399,7 @@ public class ConnectivityManager {
|
|||||||
*/
|
*/
|
||||||
public ConnectivityManager(IConnectivityManager service) {
|
public ConnectivityManager(IConnectivityManager service) {
|
||||||
mService = checkNotNull(service, "missing IConnectivityManager");
|
mService = checkNotNull(service, "missing IConnectivityManager");
|
||||||
|
sInstance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
@@ -1413,6 +1421,18 @@ public class ConnectivityManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
* Get the set of tetherable, available interfaces. This list is limited by
|
||||||
* device configuration and current interface existence.
|
* device configuration and current interface existence.
|
||||||
@@ -1744,20 +1764,26 @@ public class ConnectivityManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the HTTP proxy settings for the current default network. Note that
|
* Get the current default HTTP proxy settings. If a global proxy is set it will be returned,
|
||||||
* if a global proxy is set, it will override any per-network setting.
|
* 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
|
* @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no
|
||||||
* HTTP proxy is active.
|
* HTTP proxy is active.
|
||||||
*
|
* @hide
|
||||||
* <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}
|
|
||||||
*/
|
*/
|
||||||
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 {
|
try {
|
||||||
return mService.getProxy();
|
return mService.getDefaultProxy();
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -2470,6 +2496,9 @@ public class ConnectivityManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (NetworkUtils.bindProcessToNetwork(netId)) {
|
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.
|
// Must flush DNS cache as new network may have different DNS resolutions.
|
||||||
InetAddress.clearDnsCache();
|
InetAddress.clearDnsCache();
|
||||||
// Must flush socket pool as idle sockets will be bound to previous network and may
|
// Must flush socket pool as idle sockets will be bound to previous network and may
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ interface IConnectivityManager
|
|||||||
|
|
||||||
void setGlobalProxy(in ProxyInfo p);
|
void setGlobalProxy(in ProxyInfo p);
|
||||||
|
|
||||||
ProxyInfo getProxy();
|
ProxyInfo getDefaultProxy();
|
||||||
|
|
||||||
void setDataDependency(int networkType, boolean met);
|
void setDataDependency(int networkType, boolean met);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.net.DatagramSocket;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.ProxySelector;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
@@ -244,16 +245,46 @@ public class Network implements Parcelable {
|
|||||||
* @see java.net.URL#openConnection()
|
* @see java.net.URL#openConnection()
|
||||||
*/
|
*/
|
||||||
public URLConnection openConnection(URL url) throws IOException {
|
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();
|
maybeInitHttpClient();
|
||||||
String protocol = url.getProtocol();
|
String protocol = url.getProtocol();
|
||||||
OkHttpClient client;
|
OkHttpClient client;
|
||||||
// TODO: HttpHandler creates OkHttpClients that share the default ResponseCache.
|
// TODO: HttpHandler creates OkHttpClients that share the default ResponseCache.
|
||||||
// Could this cause unexpected behavior?
|
// Could this cause unexpected behavior?
|
||||||
// TODO: Should the network's proxy be specified?
|
|
||||||
if (protocol.equals("http")) {
|
if (protocol.equals("http")) {
|
||||||
client = HttpHandler.createHttpOkHttpClient(null /* proxy */);
|
client = HttpHandler.createHttpOkHttpClient(proxy);
|
||||||
} else if (protocol.equals("https")) {
|
} else if (protocol.equals("https")) {
|
||||||
client = HttpsHandler.createHttpsOkHttpClient(null /* proxy */);
|
client = HttpsHandler.createHttpsOkHttpClient(proxy);
|
||||||
} else {
|
} else {
|
||||||
// OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
|
// OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if
|
||||||
// passed another protocol.
|
// passed another protocol.
|
||||||
|
|||||||
@@ -260,7 +260,8 @@ public class ProxyInfo implements Parcelable {
|
|||||||
if (!Uri.EMPTY.equals(mPacFileUrl)) {
|
if (!Uri.EMPTY.equals(mPacFileUrl)) {
|
||||||
sb.append("PAC Script: ");
|
sb.append("PAC Script: ");
|
||||||
sb.append(mPacFileUrl);
|
sb.append(mPacFileUrl);
|
||||||
} else if (mHost != null) {
|
}
|
||||||
|
if (mHost != null) {
|
||||||
sb.append("[");
|
sb.append("[");
|
||||||
sb.append(mHost);
|
sb.append(mHost);
|
||||||
sb.append("] ");
|
sb.append("] ");
|
||||||
|
|||||||
@@ -23,12 +23,10 @@ import android.content.Intent;
|
|||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.ConnectivityManager.NetworkCallback;
|
import android.net.ConnectivityManager.NetworkCallback;
|
||||||
import android.net.LinkProperties;
|
|
||||||
import android.net.Network;
|
import android.net.Network;
|
||||||
import android.net.NetworkCapabilities;
|
import android.net.NetworkCapabilities;
|
||||||
import android.net.NetworkRequest;
|
import android.net.NetworkRequest;
|
||||||
import android.net.Proxy;
|
import android.net.Proxy;
|
||||||
import android.net.ProxyInfo;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -96,26 +94,10 @@ public class CaptivePortalLoginActivity extends Activity {
|
|||||||
done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS);
|
done(CAPTIVE_PORTAL_APP_RETURN_WANTED_AS_IS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ConnectivityManager cm = ConnectivityManager.from(this);
|
||||||
final Network network = new Network(mNetId);
|
final Network network = new Network(mNetId);
|
||||||
ConnectivityManager.setProcessDefaultNetwork(network);
|
// Also initializes proxy system properties.
|
||||||
|
cm.setProcessDefaultNetwork(network);
|
||||||
// Set HTTP proxy system properties to those of the selected Network.
|
|
||||||
final LinkProperties lp = ConnectivityManager.from(this).getLinkProperties(network);
|
|
||||||
if (lp != null) {
|
|
||||||
final ProxyInfo proxyInfo = lp.getHttpProxy();
|
|
||||||
String host = "";
|
|
||||||
String port = "";
|
|
||||||
String exclList = "";
|
|
||||||
Uri pacFileUrl = Uri.EMPTY;
|
|
||||||
if (proxyInfo != null) {
|
|
||||||
host = proxyInfo.getHost();
|
|
||||||
port = Integer.toString(proxyInfo.getPort());
|
|
||||||
exclList = proxyInfo.getExclusionListAsString();
|
|
||||||
pacFileUrl = proxyInfo.getPacFileUrl();
|
|
||||||
}
|
|
||||||
Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl);
|
|
||||||
Log.v(TAG, "Set proxy system properties to " + proxyInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proxy system properties must be initialized before setContentView is called because
|
// Proxy system properties must be initialized before setContentView is called because
|
||||||
// setContentView initializes the WebView logic which in turn reads the system properties.
|
// setContentView initializes the WebView logic which in turn reads the system properties.
|
||||||
@@ -124,8 +106,7 @@ public class CaptivePortalLoginActivity extends Activity {
|
|||||||
getActionBar().setDisplayShowHomeEnabled(false);
|
getActionBar().setDisplayShowHomeEnabled(false);
|
||||||
|
|
||||||
// Exit app if Network disappears.
|
// Exit app if Network disappears.
|
||||||
final NetworkCapabilities networkCapabilities =
|
final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
|
||||||
ConnectivityManager.from(this).getNetworkCapabilities(network);
|
|
||||||
if (networkCapabilities == null) {
|
if (networkCapabilities == null) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -140,7 +121,7 @@ public class CaptivePortalLoginActivity extends Activity {
|
|||||||
for (int transportType : networkCapabilities.getTransportTypes()) {
|
for (int transportType : networkCapabilities.getTransportTypes()) {
|
||||||
builder.addTransportType(transportType);
|
builder.addTransportType(transportType);
|
||||||
}
|
}
|
||||||
ConnectivityManager.from(this).registerNetworkCallback(builder.build(), mNetworkCallback);
|
cm.registerNetworkCallback(builder.build(), mNetworkCallback);
|
||||||
|
|
||||||
final WebView myWebView = (WebView) findViewById(R.id.webview);
|
final WebView myWebView = (WebView) findViewById(R.id.webview);
|
||||||
myWebView.clearCache(true);
|
myWebView.clearCache(true);
|
||||||
|
|||||||
@@ -2585,7 +2585,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProxyInfo getProxy() {
|
public ProxyInfo getDefaultProxy() {
|
||||||
// this information is already available as a world read/writable jvm property
|
// 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
|
// so this API change wouldn't have a benifit. It also breaks the passing
|
||||||
// of proxy info to all the JVMs.
|
// of proxy info to all the JVMs.
|
||||||
@@ -2597,6 +2597,34 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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) {
|
public void setGlobalProxy(ProxyInfo proxyProperties) {
|
||||||
enforceConnectivityInternalPermission();
|
enforceConnectivityInternalPermission();
|
||||||
|
|
||||||
@@ -2714,6 +2742,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the proxy has changed from oldLp to newLp, resend proxy broadcast with default proxy.
|
||||||
|
// This method gets called when any network changes proxy, but the broadcast only ever contains
|
||||||
|
// 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) {
|
||||||
|
ProxyInfo newProxyInfo = newLp == null ? null : newLp.getHttpProxy();
|
||||||
|
ProxyInfo oldProxyInfo = oldLp == null ? null : oldLp.getHttpProxy();
|
||||||
|
|
||||||
|
if (!proxyInfoEqual(newProxyInfo, oldProxyInfo)) {
|
||||||
|
sendProxyBroadcast(getDefaultProxy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleDeprecatedGlobalHttpProxy() {
|
private void handleDeprecatedGlobalHttpProxy() {
|
||||||
String proxy = Settings.Global.getString(mContext.getContentResolver(),
|
String proxy = Settings.Global.getString(mContext.getContentResolver(),
|
||||||
Settings.Global.HTTP_PROXY);
|
Settings.Global.HTTP_PROXY);
|
||||||
@@ -3627,7 +3669,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
|
updateDnses(newLp, oldLp, netId, flushDns, useDefaultDns);
|
||||||
|
|
||||||
updateClat(newLp, oldLp, networkAgent);
|
updateClat(newLp, oldLp, networkAgent);
|
||||||
if (isDefaultNetwork(networkAgent)) handleApplyDefaultProxy(newLp.getHttpProxy());
|
if (isDefaultNetwork(networkAgent)) {
|
||||||
|
handleApplyDefaultProxy(newLp.getHttpProxy());
|
||||||
|
} else {
|
||||||
|
updateProxy(newLp, oldLp, networkAgent);
|
||||||
|
}
|
||||||
// TODO - move this check to cover the whole function
|
// TODO - move this check to cover the whole function
|
||||||
if (!Objects.equals(newLp, oldLp)) {
|
if (!Objects.equals(newLp, oldLp)) {
|
||||||
notifyIfacesChanged();
|
notifyIfacesChanged();
|
||||||
|
|||||||
Reference in New Issue
Block a user