Query HTTP proxy for network via a new API to avoid permissions exceptions

Add @hidden ConnectivityManager.getProxyForNetwork() API.

Bug:20470604
Change-Id: I6a9bc4afc8273bc43b14cdeccfedbbf3ff66be40
This commit is contained in:
Paul Jensen
2015-05-06 07:32:40 -04:00
parent 96011f4e3a
commit db93dd93c5
6 changed files with 54 additions and 24 deletions

View File

@@ -1904,9 +1904,6 @@ public class ConnectivityManager {
* *
* @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null}
* if no global HTTP proxy is set. * if no global HTTP proxy is set.
*
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
* @hide * @hide
*/ */
public ProxyInfo getGlobalProxy() { public ProxyInfo getGlobalProxy() {
@@ -1917,6 +1914,28 @@ public class ConnectivityManager {
} }
} }
/**
* Retrieve the global HTTP proxy, or if no global HTTP proxy is set, a
* network-specific HTTP proxy. If {@code network} is null, the
* network-specific proxy returned is the proxy of the default active
* network.
*
* @return {@link ProxyInfo} for the current global HTTP proxy, or if no
* global HTTP proxy is set, {@code ProxyInfo} for {@code network},
* or when {@code network} is {@code null},
* the {@code ProxyInfo} for the default active network. Returns
* {@code null} when no proxy applies or the caller doesn't have
* permission to use {@code network}.
* @hide
*/
public ProxyInfo getProxyForNetwork(Network network) {
try {
return mService.getProxyForNetwork(network);
} catch (RemoteException e) {
return null;
}
}
/** /**
* Get the current default HTTP proxy settings. If a global proxy is set it will be returned, * 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 * otherwise if this process is bound to a {@link Network} using
@@ -1927,19 +1946,7 @@ public class ConnectivityManager {
* HTTP proxy is active. * HTTP proxy is active.
*/ */
public ProxyInfo getDefaultProxy() { public ProxyInfo getDefaultProxy() {
final Network network = getBoundNetworkForProcess(); return getProxyForNetwork(getBoundNetworkForProcess());
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.getDefaultProxy();
} catch (RemoteException e) {
return null;
}
} }
/** /**

View File

@@ -104,7 +104,7 @@ interface IConnectivityManager
void setGlobalProxy(in ProxyInfo p); void setGlobalProxy(in ProxyInfo p);
ProxyInfo getDefaultProxy(); ProxyInfo getProxyForNetwork(in Network nework);
boolean prepareVpn(String oldPackage, String newPackage); boolean prepareVpn(String oldPackage, String newPackage);

View File

@@ -247,12 +247,7 @@ public class Network implements Parcelable {
throw new IOException("No ConnectivityManager yet constructed, please construct one"); throw new IOException("No ConnectivityManager yet constructed, please construct one");
} }
// TODO: Should this be optimized to avoid fetching the global proxy for every request? // TODO: Should this be optimized to avoid fetching the global proxy for every request?
ProxyInfo proxyInfo = cm.getGlobalProxy(); final ProxyInfo proxyInfo = cm.getProxyForNetwork(this);
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; java.net.Proxy proxy = null;
if (proxyInfo != null) { if (proxyInfo != null) {
proxy = proxyInfo.makeProxy(); proxy = proxyInfo.makeProxy();

View File

@@ -193,6 +193,12 @@ public class NetworkUtils {
*/ */
public native static boolean protectFromVpn(int socketfd); public native static boolean protectFromVpn(int socketfd);
/**
* Determine if {@code uid} can access network designated by {@code netId}.
* @return {@code true} if {@code uid} can access network, {@code false} otherwise.
*/
public native static boolean queryUserAccess(int uid, int netId);
/** /**
* Convert a IPv4 address from an integer to an InetAddress. * Convert a IPv4 address from an integer to an InetAddress.
* @param hostAddress an int corresponding to the IPv4 address in network byte order * @param hostAddress an int corresponding to the IPv4 address in network byte order

View File

@@ -291,6 +291,11 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint
return (jboolean) !protectFromVpn(socket); return (jboolean) !protectFromVpn(socket);
} }
static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
{
return (jboolean) !queryUserAccess(uid, netId);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -311,6 +316,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter }, { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
}; };

View File

@@ -2626,7 +2626,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
actionToken); actionToken);
} }
public ProxyInfo getDefaultProxy() { private 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.
@@ -2638,6 +2638,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
public ProxyInfo getProxyForNetwork(Network network) {
if (network == null) return getDefaultProxy();
final ProxyInfo globalProxy = 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
// caller may not have.
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai == null) return null;
synchronized (nai) {
final ProxyInfo proxyInfo = nai.linkProperties.getHttpProxy();
if (proxyInfo == null) return null;
return new ProxyInfo(proxyInfo);
}
}
// Convert empty ProxyInfo's to null as null-checks are used to determine if proxies are present // 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 // (e.g. if mGlobalProxy==null fall back to network-specific proxy, if network-specific
// proxy is null then there is no proxy in place). // proxy is null then there is no proxy in place).