Notify all VMs when proxy changes.

bug:2700664
Change-Id: I74cc6e0bd6e66847bf18f524ce851e3e9d2c4e87
This commit is contained in:
Robert Greenwalt
2010-10-11 16:00:27 -07:00
parent f93a7e934e
commit c3c5f865a3
4 changed files with 285 additions and 42 deletions

View File

@@ -624,4 +624,39 @@ public class ConnectivityManager
} catch (RemoteException e) {
}
}
/**
* @param proxyProperties The definition for the new global http proxy
* {@hide}
*/
public void setGlobalProxy(ProxyProperties p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
}
}
/**
* @return proxyProperties for the current global proxy
* {@hide}
*/
public ProxyProperties getGlobalProxy() {
try {
return mService.getGlobalProxy();
} catch (RemoteException e) {
return null;
}
}
/**
* @return proxyProperties for the current proxy (global if set, network specific if not)
* {@hide}
*/
public ProxyProperties getProxy() {
try {
return mService.getProxy();
} catch (RemoteException e) {
return null;
}
}
}

View File

@@ -18,6 +18,7 @@ package android.net;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.ProxyProperties;
import android.os.IBinder;
/**
@@ -85,4 +86,10 @@ interface IConnectivityManager
void requestNetworkTransitionWakelock(in String forWhom);
void reportInetCondition(int networkType, int percentage);
ProxyProperties getGlobalProxy();
void setGlobalProxy(in ProxyProperties p);
ProxyProperties getProxy();
}

View File

@@ -19,6 +19,8 @@ package android.net;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -30,44 +32,108 @@ import java.net.UnknownHostException;
*/
public class ProxyProperties implements Parcelable {
private InetSocketAddress mProxy;
private String mHost;
private int mPort;
private String mExclusionList;
private String[] mParsedExclusionList;
public ProxyProperties() {
public ProxyProperties(String host, int port, String exclList) {
mHost = host;
mPort = port;
setExclusionList(exclList);
}
private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
mHost = host;
mPort = port;
mExclusionList = exclList;
mParsedExclusionList = parsedExclList;
}
// copy constructor instead of clone
public ProxyProperties(ProxyProperties source) {
if (source != null) {
mProxy = source.getSocketAddress();
String exclusionList = source.getExclusionList();
if (exclusionList != null) {
mExclusionList = new String(exclusionList);
}
mHost = source.getHost();
mPort = source.getPort();
mExclusionList = source.getExclusionList();
mParsedExclusionList = source.mParsedExclusionList;
}
}
public InetSocketAddress getSocketAddress() {
return mProxy;
InetSocketAddress inetSocketAddress = null;
try {
inetSocketAddress = new InetSocketAddress(mHost, mPort);
} catch (IllegalArgumentException e) { }
return inetSocketAddress;
}
public void setSocketAddress(InetSocketAddress proxy) {
mProxy = proxy;
public String getHost() {
return mHost;
}
public int getPort() {
return mPort;
}
// comma separated
public String getExclusionList() {
return mExclusionList;
}
public void setExclusionList(String exclusionList) {
// comma separated
private void setExclusionList(String exclusionList) {
mExclusionList = exclusionList;
if (mExclusionList == null) {
mParsedExclusionList = new String[0];
} else {
String splitExclusionList[] = exclusionList.toLowerCase().split(",");
mParsedExclusionList = new String[splitExclusionList.length * 2];
for (int i = 0; i < splitExclusionList.length; i++) {
String s = splitExclusionList[i].trim();
if (s.startsWith(".")) s = s.substring(1);
mParsedExclusionList[i*2] = s;
mParsedExclusionList[(i*2)+1] = "." + s;
}
}
}
public boolean isExcluded(String url) {
if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
mParsedExclusionList.length == 0) return false;
Uri u = Uri.parse(url);
String urlDomain = u.getHost();
if (urlDomain == null) return false;
for (int i = 0; i< mParsedExclusionList.length; i+=2) {
if (urlDomain.equals(mParsedExclusionList[i]) ||
urlDomain.endsWith(mParsedExclusionList[i+1])) {
return true;
}
}
return false;
}
public java.net.Proxy makeProxy() {
java.net.Proxy proxy = java.net.Proxy.NO_PROXY;
if (mHost != null) {
try {
InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort);
proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress);
} catch (IllegalArgumentException e) {
}
}
return proxy;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (mProxy != null) {
sb.append(mProxy.toString());
if (mHost != null) {
sb.append("[");
sb.append(mHost);
sb.append("] ");
sb.append(Integer.toString(mPort));
if (mExclusionList != null) {
sb.append(" xl=").append(mExclusionList);
}
@@ -75,6 +141,20 @@ public class ProxyProperties implements Parcelable {
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ProxyProperties)) return false;
ProxyProperties p = (ProxyProperties)o;
if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
return false;
}
if (mHost != null && p.mHost == null) return false;
if (mHost == null && p.mHost != null) return false;
if (mPort != p.mPort) return false;
return true;
}
/**
* Implement the Parcelable interface
* @hide
@@ -88,27 +168,15 @@ public class ProxyProperties implements Parcelable {
* @hide
*/
public void writeToParcel(Parcel dest, int flags) {
String host = null;
if (mProxy != null) {
try {
InetAddress addr = mProxy.getAddress();
if (addr != null) {
host = addr.getHostAddress();
} else {
/* Does not resolve when addr is null */
host = mProxy.getHostName();
}
} catch (Exception e) { }
}
if (host != null) {
if (mHost != null) {
dest.writeByte((byte)1);
dest.writeString(host);
dest.writeInt(mProxy.getPort());
dest.writeString(mHost);
dest.writeInt(mPort);
} else {
dest.writeByte((byte)0);
}
dest.writeString(mExclusionList);
dest.writeStringArray(mParsedExclusionList);
}
/**
@@ -118,16 +186,16 @@ public class ProxyProperties implements Parcelable {
public static final Creator<ProxyProperties> CREATOR =
new Creator<ProxyProperties>() {
public ProxyProperties createFromParcel(Parcel in) {
ProxyProperties proxyProperties = new ProxyProperties();
String host = null;
int port = 0;
if (in.readByte() == 1) {
try {
String host = in.readString();
int port = in.readInt();
proxyProperties.setSocketAddress(InetSocketAddress.createUnresolved(
host, port));
} catch (IllegalArgumentException e) { }
host = in.readString();
port = in.readInt();
}
proxyProperties.setExclusionList(in.readString());
String exclList = in.readString();
String[] parsedExclList = in.readStringArray();
ProxyProperties proxyProperties =
new ProxyProperties(host, port, exclList, parsedExclList);
return proxyProperties;
}

View File

@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.MobileDataStateTracker;
@@ -29,8 +30,9 @@ import android.net.NetworkInfo;
import android.net.LinkProperties;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyProperties;
import android.net.wifi.WifiStateTracker;
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -55,13 +57,12 @@ import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.List;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* @hide
@@ -179,6 +180,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK =
MAX_NETWORK_STATE_TRACKER_EVENT + 8;
/**
* used internally to reload global proxy settings
*/
private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
MAX_NETWORK_STATE_TRACKER_EVENT + 9;
private Handler mHandler;
// list of DeathRecipients used to make sure features are turned off when
@@ -199,6 +206,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
// track the current default http proxy - tell the world if we get a new one (real change)
private ProxyProperties mDefaultProxy = null;
// track the global proxy.
private ProxyProperties mGlobalProxy = null;
private final Object mGlobalProxyLock = new Object();
private SettingsObserver mSettingsObserver;
private static class NetworkAttributes {
/**
* Class for holding settings read from resources.
@@ -412,6 +427,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (DBG) {
mInetLog = new ArrayList();
}
mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
mSettingsObserver.observe(mContext);
}
@@ -1303,6 +1321,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mInitialBroadcast = null;
}
}
// load the global proxy at startup
mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
}
private void handleConnect(NetworkInfo info) {
@@ -1380,6 +1400,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
if (mNetAttributes[netType].isDefault()) {
handleApplyDefaultProxy(netType);
addDefaultRoute(mNetTrackers[netType]);
} else {
addPrivateDnsRoutes(mNetTrackers[netType]);
@@ -1783,10 +1804,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
break;
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
// TODO - make this handle ip/proxy/gateway/dns changes
info = (NetworkInfo) msg.obj;
type = info.getType();
handleDnsConfigurationChange(type);
handleConnectivityChange(type);
break;
case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
String causedBy = null;
@@ -1838,6 +1858,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
handleSetMobileData(enabled);
break;
}
case EVENT_APPLY_GLOBAL_HTTP_PROXY:
{
handleDeprecatedGlobalHttpProxy();
}
}
}
}
@@ -2037,4 +2061,113 @@ public class ConnectivityService extends IConnectivityManager.Stub {
sendInetConditionBroadcast(networkInfo);
return;
}
public synchronized ProxyProperties getProxy() {
if (mGlobalProxy != null) return mGlobalProxy;
if (mDefaultProxy != null) return mDefaultProxy;
return null;
}
public void setGlobalProxy(ProxyProperties proxyProperties) {
enforceChangePermission();
synchronized (mGlobalProxyLock) {
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 = "";
if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
mGlobalProxy = new ProxyProperties(proxyProperties);
host = mGlobalProxy.getHost();
port = mGlobalProxy.getPort();
exclList = mGlobalProxy.getExclusionList();
} else {
mGlobalProxy = null;
}
ContentResolver res = mContext.getContentResolver();
Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
Settings.Secure.putString(res,Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
exclList);
}
if (mGlobalProxy == null) {
proxyProperties = mDefaultProxy;
}
sendProxyBroadcast(proxyProperties);
}
public ProxyProperties getGlobalProxy() {
synchronized (mGlobalProxyLock) {
return mGlobalProxy;
}
}
private void handleApplyDefaultProxy(int type) {
// check if new default - push it out to all VM if so
ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy();
synchronized (this) {
if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
if (mDefaultProxy == proxy) return;
if (!TextUtils.isEmpty(proxy.getHost())) {
mDefaultProxy = proxy;
} else {
mDefaultProxy = null;
}
}
if (DBG) Slog.d(TAG, "changing default proxy to " + proxy);
if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
if (mGlobalProxy != null) return;
sendProxyBroadcast(proxy);
}
private void handleDeprecatedGlobalHttpProxy() {
String proxy = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.HTTP_PROXY);
if (!TextUtils.isEmpty(proxy)) {
String data[] = proxy.split(":");
String proxyHost = data[0];
int proxyPort = 8080;
if (data.length > 1) {
try {
proxyPort = Integer.parseInt(data[1]);
} catch (NumberFormatException e) {
return;
}
}
ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
setGlobalProxy(p);
}
}
private void sendProxyBroadcast(ProxyProperties proxy) {
Slog.d(TAG, "sending Proxy Broadcast for " + proxy);
Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy);
mContext.sendBroadcast(intent);
}
private static class SettingsObserver extends ContentObserver {
private int mWhat;
private Handler mHandler;
SettingsObserver(Handler handler, int what) {
super(handler);
mHandler = handler;
mWhat = what;
}
void observe(Context context) {
ContentResolver resolver = context.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.HTTP_PROXY), false, this);
}
@Override
public void onChange(boolean selfChange) {
mHandler.obtainMessage(mWhat).sendToTarget();
}
}
}