diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index b483f6cfdf1b2..dd9c8f09bd16e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -264,6 +264,24 @@ public class ConnectivityManager } } + /** @hide */ + public LinkProperties getActiveLinkProperties() { + try { + return mService.getActiveLinkProperties(); + } catch (RemoteException e) { + return null; + } + } + + /** @hide */ + public LinkProperties getLinkProperties(int networkType) { + try { + return mService.getLinkProperties(networkType); + } catch (RemoteException e) { + return null; + } + } + /** {@hide} */ public boolean setRadios(boolean turnOn) { try { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 9f2fc17ae2154..35054d6c40945 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.LinkProperties; import android.net.NetworkInfo; import android.os.IBinder; @@ -36,6 +37,10 @@ interface IConnectivityManager NetworkInfo[] getAllNetworkInfo(); + LinkProperties getActiveLinkProperties(); + + LinkProperties getLinkProperties(int networkType); + boolean setRadios(boolean onOff); boolean setRadio(int networkType, boolean turnOn); diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 9c63cd9c33e56..830ff06b5c624 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -21,21 +21,31 @@ import android.content.Context; import android.database.ContentObserver; import android.os.Handler; import android.os.SystemProperties; +import android.text.TextUtils; import android.provider.Settings; +import android.util.Log; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.ProxySelector; import java.net.SocketAddress; import java.net.URI; import java.net.UnknownHostException; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.Assert; +import org.apache.http.conn.routing.HttpRoute; +import org.apache.http.conn.routing.HttpRoutePlanner; +import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.impl.conn.ProxySelectorRoutePlanner; +import org.apache.http.protocol.HttpContext; /** * A convenience class for accessing the user and default proxy @@ -57,6 +67,8 @@ public final class Proxy { private static ProxySpec sGlobalProxySpec = null; + private static ConnectivityManager sConnectivityManager = null; + // Hostname / IP REGEX validation // Matches blank input, ips, and domain names private static final String NAME_IP_REGEX = @@ -78,13 +90,15 @@ public final class Proxy { // useful because it holds the processed exclusion list - don't want to reparse it each time private static class ProxySpec { - String[] exclusionList = null; + String[] exclusionList; InetSocketAddress address = null; - public ProxySpec() { }; + public ProxySpec() { + exclusionList = new String[0]; + }; } - private static boolean isURLInExclusionListReadLocked(String url, String[] exclusionList) { - if (exclusionList == null) { + private static boolean isURLInExclusionList(String url, String[] exclusionList) { + if (url == null) { return false; } Uri u = Uri.parse(url); @@ -149,7 +163,7 @@ public final class Proxy { } if (sGlobalProxySpec != null) { // Proxy defined - Apply exclusion rules - if (isURLInExclusionListReadLocked(url, sGlobalProxySpec.exclusionList)) { + if (isURLInExclusionList(url, sGlobalProxySpec.exclusionList)) { // Return no proxy retval = java.net.Proxy.NO_PROXY; } else { @@ -157,13 +171,7 @@ public final class Proxy { new java.net.Proxy(java.net.Proxy.Type.HTTP, sGlobalProxySpec.address); } } else { - // If network is WiFi, return no proxy. - // Otherwise, return the Mobile Operator proxy. - if (!isNetworkWifi(ctx)) { - retval = getDefaultProxy(url); - } else { - retval = java.net.Proxy.NO_PROXY; - } + retval = getDefaultProxy(ctx, url); } } finally { sProxyInfoLock.readLock().unlock(); @@ -183,19 +191,12 @@ public final class Proxy { * host is to be used. */ public static final String getHost(Context ctx) { - sProxyInfoLock.readLock().lock(); + java.net.Proxy proxy = getProxy(ctx, null); + if (proxy == java.net.Proxy.NO_PROXY) return null; try { - if (sGlobalProxyChangedObserver == null) { - registerContentObserversReadLocked(ctx); - parseGlobalProxyInfoReadLocked(ctx); - } - if (sGlobalProxySpec != null) { - InetSocketAddress sa = sGlobalProxySpec.address; - return sa.getHostName(); - } - return getDefaultHost(); - } finally { - sProxyInfoLock.readLock().unlock(); + return ((InetSocketAddress)(proxy.address())).getHostName(); + } catch (Exception e) { + return null; } } @@ -206,19 +207,12 @@ public final class Proxy { * @return The port number to use or -1 if no proxy is to be used. */ public static final int getPort(Context ctx) { - sProxyInfoLock.readLock().lock(); + java.net.Proxy proxy = getProxy(ctx, null); + if (proxy == java.net.Proxy.NO_PROXY) return -1; try { - if (sGlobalProxyChangedObserver == null) { - registerContentObserversReadLocked(ctx); - parseGlobalProxyInfoReadLocked(ctx); - } - if (sGlobalProxySpec != null) { - InetSocketAddress sa = sGlobalProxySpec.address; - return sa.getPort(); - } - return getDefaultPort(); - } finally { - sProxyInfoLock.readLock().unlock(); + return ((InetSocketAddress)(proxy.address())).getPort(); + } catch (Exception e) { + return -1; } } @@ -229,14 +223,7 @@ public final class Proxy { * this carrier. */ public static final String getDefaultHost() { - String host = SystemProperties.get("net.gprs.http-proxy"); - if ((host != null) && (host.length() != 0)) { - Uri u = Uri.parse(host); - host = u.getHost(); - return host; - } else { - return null; - } + return null; } // TODO: deprecate this function @@ -246,26 +233,36 @@ public final class Proxy { * no proxy for this carrier. */ public static final int getDefaultPort() { - String host = SystemProperties.get("net.gprs.http-proxy"); - if ((host != null) && (host.length() != 0)) { - Uri u = Uri.parse(host); - return u.getPort(); - } else { - return -1; - } + return -1; } - private static final java.net.Proxy getDefaultProxy(String url) { - // TODO: This will go away when information is collected from ConnectivityManager... - // There are broadcast of network proxies, so they are parse manually. - String host = SystemProperties.get("net.gprs.http-proxy"); - if ((host != null) && (host.length() != 0)) { - Uri u = Uri.parse(host); - return new java.net.Proxy(java.net.Proxy.Type.HTTP, - new InetSocketAddress(u.getHost(), u.getPort())); - } else { - return java.net.Proxy.NO_PROXY; + // TODO - cache the details for each network so we don't have to fetch and parse + // on each request + private static final java.net.Proxy getDefaultProxy(Context context, String url) { + if (sConnectivityManager == null) { + sConnectivityManager = (ConnectivityManager)context.getSystemService( + Context.CONNECTIVITY_SERVICE); } + if (sConnectivityManager == null) return java.net.Proxy.NO_PROXY; + + LinkProperties linkProperties = sConnectivityManager.getActiveLinkProperties(); + + if (linkProperties != null) { + ProxyProperties proxyProperties = linkProperties.getHttpProxy(); + + if (proxyProperties != null) { + String exclusionList = proxyProperties.getExclusionList(); + SocketAddress socketAddr = proxyProperties.getSocketAddress(); + if (socketAddr != null) { + String[] parsedExclusionArray = + parsedExclusionArray = parseExclusionList(exclusionList); + if (!isURLInExclusionList(url, parsedExclusionArray)) { + return new java.net.Proxy(java.net.Proxy.Type.HTTP, socketAddr); + } + } + } + } + return java.net.Proxy.NO_PROXY; } // TODO: remove this function / deprecate @@ -317,22 +314,6 @@ public final class Proxy { return false; } - private static final boolean isNetworkWifi(Context context) { - if (context == null) { - return false; - } - final ConnectivityManager connectivity = (ConnectivityManager) - context.getSystemService(Context.CONNECTIVITY_SERVICE); - if (connectivity != null) { - final NetworkInfo info = connectivity.getActiveNetworkInfo(); - if (info != null && - info.getType() == ConnectivityManager.TYPE_WIFI) { - return true; - } - } - return false; - } - private static class SettingsObserver extends ContentObserver { private Context mContext; @@ -376,7 +357,7 @@ public final class Proxy { String proxyHost = Settings.Secure.getString( contentResolver, Settings.Secure.HTTP_PROXY); - if ((proxyHost == null) || (proxyHost.length() == 0)) { + if (TextUtils.isEmpty(proxyHost)) { // Clear signal sProxyInfoLock.readLock().unlock(); sProxyInfoLock.writeLock().lock(); @@ -390,36 +371,35 @@ public final class Proxy { Settings.Secure.HTTP_PROXY_EXCLUSION_LIST); String host = parseHost(proxyHost); int port = parsePort(proxyHost); + ProxySpec tmpProxySpec = null; if (proxyHost != null) { - sGlobalProxySpec = new ProxySpec(); - sGlobalProxySpec.address= new InetSocketAddress(host, port); - if ((exclusionListSpec != null) && (exclusionListSpec.length() != 0)) { - String[] exclusionListEntries = exclusionListSpec.toLowerCase().split(","); - String[] processedEntries = new String[exclusionListEntries.length]; - for (int i = 0; i < exclusionListEntries.length; i++) { - String entry = exclusionListEntries[i].trim(); - if (entry.startsWith(".")) { - entry = entry.substring(1); - } - processedEntries[i] = entry; - } - sProxyInfoLock.readLock().unlock(); - sProxyInfoLock.writeLock().lock(); - sGlobalProxySpec.exclusionList = processedEntries; - } else { - sProxyInfoLock.readLock().unlock(); - sProxyInfoLock.writeLock().lock(); - sGlobalProxySpec.exclusionList = null; - } - } else { - sProxyInfoLock.readLock().unlock(); - sProxyInfoLock.writeLock().lock(); - sGlobalProxySpec = null; + tmpProxySpec = new ProxySpec(); + tmpProxySpec.address = new InetSocketAddress(host, port); + tmpProxySpec.exclusionList = parseExclusionList(exclusionListSpec); } + sProxyInfoLock.readLock().unlock(); + sProxyInfoLock.writeLock().lock(); + sGlobalProxySpec = tmpProxySpec; sProxyInfoLock.readLock().lock(); sProxyInfoLock.writeLock().unlock(); } + private static String[] parseExclusionList(String exclusionList) { + String[] processedArray = new String[0]; + if (!TextUtils.isEmpty(exclusionList)) { + String[] exclusionListArray = exclusionList.toLowerCase().split(","); + processedArray = new String[exclusionListArray.length]; + for (int i = 0; i < exclusionListArray.length; i++) { + String entry = exclusionListArray[i].trim(); + if (entry.startsWith(".")) { + entry = entry.substring(1); + } + processedArray[i] = entry; + } + } + return processedArray; + } + /** * Validate syntax of hostname, port and exclusion list entries * {@hide} @@ -455,4 +435,46 @@ public final class Proxy { } } } + + static class AndroidProxySelectorRoutePlanner + extends org.apache.http.impl.conn.ProxySelectorRoutePlanner { + + private Context mContext; + + public AndroidProxySelectorRoutePlanner(SchemeRegistry schreg, ProxySelector prosel, + Context context) { + super(schreg, prosel); + mContext = context; + } + + @Override + protected java.net.Proxy chooseProxy(List proxies, HttpHost target, + HttpRequest request, HttpContext context) { + return getProxy(mContext, target.getHostName()); + } + + @Override + protected HttpHost determineProxy(HttpHost target, HttpRequest request, + HttpContext context) { + return getPreferredHttpHost(mContext, target.getHostName()); + } + + @Override + public HttpRoute determineRoute(HttpHost target, HttpRequest request, + HttpContext context) { + HttpHost proxy = getPreferredHttpHost(mContext, target.getHostName()); + if (proxy == null) { + return new HttpRoute(target); + } else { + return new HttpRoute(target, null, proxy, false); + } + } + } + + /** @hide */ + public static final HttpRoutePlanner getAndroidProxySelectorRoutePlanner(Context context) { + AndroidProxySelectorRoutePlanner ret = new AndroidProxySelectorRoutePlanner( + new SchemeRegistry(), ProxySelector.getDefault(), context); + return ret; + } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6935e92961305..315bb876128f0 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -463,6 +463,38 @@ public class ConnectivityService extends IConnectivityManager.Stub { return result; } + /** + * Return LinkProperties for the active (i.e., connected) default + * network interface. It is assumed that at most one default network + * is active at a time. If more than one is active, it is indeterminate + * which will be returned. + * @return the ip properties for the active network, or {@code null} if + * none is active + */ + public LinkProperties getActiveLinkProperties() { + enforceAccessPermission(); + for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { + continue; + } + NetworkStateTracker t = mNetTrackers[type]; + NetworkInfo info = t.getNetworkInfo(); + if (info.isConnected()) { + return t.getLinkProperties(); + } + } + return null; + } + + public LinkProperties getLinkProperties(int networkType) { + enforceAccessPermission(); + if (ConnectivityManager.isNetworkTypeValid(networkType)) { + NetworkStateTracker t = mNetTrackers[networkType]; + if (t != null) return t.getLinkProperties(); + } + return null; + } + public boolean setRadios(boolean turnOn) { boolean result = true; enforceChangePermission();