summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Oscar Montemayor <oam@google.com> 2010-08-03 10:51:06 -0700
committer Oscar Montemayor <oam@google.com> 2010-08-04 16:01:56 -0700
commit69238c6a37ae43c748ad9cd7613f2209149ee7da (patch)
treefc77df6662f66584d96d4c035a4ef719f9d87934
parenta69fbc8effd5aaf7a5eeafed0c0fc69bcd3e7e15 (diff)
Device Policy Manager changes to enable Global Proxy.
Change-Id: I8489df7d28e4c5312e10d5cecc8e2a182413a034
-rw-r--r--api/current.xml28
-rw-r--r--core/java/android/app/admin/DeviceAdminInfo.java15
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java90
-rw-r--r--core/java/android/app/admin/IDevicePolicyManager.aidl3
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java137
6 files changed, 277 insertions, 1 deletions
diff --git a/api/current.xml b/api/current.xml
index d87acf941b8d..5b17c2bfcf01 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -34339,6 +34339,17 @@
visibility="public"
>
</method>
+<method name="getGlobalProxyAdmin"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getMaximumFailedPasswordsForWipe"
return="int"
abstract="false"
@@ -34558,6 +34569,23 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="setGlobalProxy"
+ return="android.content.ComponentName"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="admin" type="android.content.ComponentName">
+</parameter>
+<parameter name="proxySpec" type="java.net.Proxy">
+</parameter>
+<parameter name="exclusionList" type="java.util.List&lt;java.lang.String&gt;">
+</parameter>
+</method>
<method name="setMaximumFailedPasswordsForWipe"
return="void"
abstract="false"
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index 0bcd65cd48fe..e09cda26674e 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -103,6 +103,16 @@ public final class DeviceAdminInfo implements Parcelable {
*/
public static final int USES_POLICY_WIPE_DATA = 4;
+ /**
+ * A type of policy that this device admin can use: able to specify the
+ * device Global Proxy, via {@link DevicePolicyManager#setGlobalProxy}.
+ *
+ * <p>To control this policy, the device admin must have a "set-global-proxy"
+ * tag in the "uses-policies" section of its meta-data.
+ * @hide
+ */
+ public static final int USES_POLICY_SETS_GLOBAL_PROXY = 5;
+
/** @hide */
public static class PolicyInfo {
public final int ident;
@@ -138,6 +148,9 @@ public final class DeviceAdminInfo implements Parcelable {
sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_FORCE_LOCK, "force-lock",
com.android.internal.R.string.policylab_forceLock,
com.android.internal.R.string.policydesc_forceLock));
+ sPoliciesDisplayOrder.add(new PolicyInfo(USES_POLICY_SETS_GLOBAL_PROXY, "set-global-proxy",
+ com.android.internal.R.string.policylab_setGlobalProxy,
+ com.android.internal.R.string.policydesc_setGlobalProxy));
for (int i=0; i<sPoliciesDisplayOrder.size(); i++) {
PolicyInfo pi = sPoliciesDisplayOrder.get(i);
@@ -328,7 +341,7 @@ public final class DeviceAdminInfo implements Parcelable {
* the given policy control. The possible policy identifier inputs are:
* {@link #USES_POLICY_LIMIT_PASSWORD}, {@link #USES_POLICY_WATCH_LOGIN},
* {@link #USES_POLICY_RESET_PASSWORD}, {@link #USES_POLICY_FORCE_LOCK},
- * {@link #USES_POLICY_WIPE_DATA}.
+ * {@link #USES_POLICY_WIPE_DATA}, {@link #USES_POLICY_SETS_GLOBAL_PROXY}.
*/
public boolean usesPolicy(int policyIdent) {
return (mUsesPolicies & (1<<policyIdent)) != 0;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3066f5ca47c9..1255e63c2a21 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -32,6 +32,8 @@ import android.os.ServiceManager;
import android.util.Log;
import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.util.List;
/**
@@ -915,6 +917,93 @@ public class DevicePolicyManager {
}
/**
+ * Called by an application that is administering the device to set the
+ * global proxy and exclusion list.
+ * <p>
+ * The calling device admin must have requested
+ * {@link DeviceAdminInfo#USES_POLICY_SETS_GLOBAL_PROXY} to be able to call
+ * this method; if it has not, a security exception will be thrown.
+ * Only the first device admin can set the proxy. If a second admin attempts
+ * to set the proxy, the {@link ComponentName} of the admin originally setting the
+ * proxy will be returned. If successful in setting the proxy, null will
+ * be returned.
+ * The method can be called repeatedly by the device admin alrady setting the
+ * proxy to update the proxy and exclusion list.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated
+ * with.
+ * @param proxySpec the global proxy desired. Must be an HTTP Proxy.
+ * Pass Proxy.NO_PROXY to reset the proxy.
+ * @param exclusionList a list of domains to be excluded from the global proxy.
+ * @param proxyAdmins an empty, mutable list that will contain any proxy admins
+ * that define a global proxy.
+ * @return returns null if the proxy was successfully set, or a {@link ComponentName}
+ * of the device admin that sets thew proxy otherwise.
+ */
+ public ComponentName setGlobalProxy(ComponentName admin, Proxy proxySpec,
+ List<String> exclusionList ) {
+ if (proxySpec == null) {
+ throw new NullPointerException();
+ }
+ if (mService != null) {
+ try {
+ String hostSpec;
+ String exclSpec;
+ if (proxySpec.equals(Proxy.NO_PROXY)) {
+ hostSpec = null;
+ exclSpec = null;
+ } else {
+ if (!proxySpec.type().equals(Proxy.Type.HTTP)) {
+ throw new IllegalArgumentException();
+ }
+ InetSocketAddress sa = (InetSocketAddress)proxySpec.address();
+ String hostName = sa.getHostName();
+ int port = sa.getPort();
+ StringBuilder hostBuilder = new StringBuilder();
+ hostSpec = hostBuilder.append(hostName)
+ .append(":").append(Integer.toString(port)).toString();
+ if (exclusionList == null) {
+ exclSpec = "";
+ } else {
+ StringBuilder listBuilder = new StringBuilder();
+ boolean firstDomain = true;
+ for (String exclDomain : exclusionList) {
+ if (!firstDomain) {
+ listBuilder = listBuilder.append(",");
+ } else {
+ firstDomain = false;
+ }
+ listBuilder = listBuilder.append(exclDomain.trim());
+ }
+ exclSpec = listBuilder.toString();
+ }
+ android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec);
+ }
+ return mService.setGlobalProxy(admin, hostSpec, exclSpec);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the component name setting the global proxy.
+ * @return ComponentName object of the device admin that set the global proxy, or
+ * null if no admin has set the proxy.
+ */
+ public ComponentName getGlobalProxyAdmin() {
+ if (mService != null) {
+ try {
+ return mService.getGlobalProxyAdmin();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed talking with device policy service", e);
+ }
+ }
+ return null;
+ }
+
+ /**
* @hide
*/
public void setActiveAdmin(ComponentName policyReceiver) {
@@ -1007,4 +1096,5 @@ public class DevicePolicyManager {
}
}
}
+
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 3ada95cf6264..3fcd6fce5140 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -66,6 +66,9 @@ interface IDevicePolicyManager {
void lockNow();
void wipeData(int flags);
+
+ ComponentName setGlobalProxy(in ComponentName admin, String proxySpec, String exclusionList);
+ ComponentName getGlobalProxyAdmin();
void setActiveAdmin(in ComponentName policyReceiver);
boolean isAdminActive(in ComponentName policyReceiver);
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0304b1dabe63..32a1f0dbed2e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1252,6 +1252,11 @@
<!-- Description of policy access to wipe the user's data -->
<string name="policydesc_wipeData">Perform a factory reset, deleting
all of your data without any confirmation.</string>
+ <string name="policylab_setGlobalProxy">Set the device global proxy</string>
+ <!-- Description of policy access to wipe the user's data -->
+ <string name="policydesc_setGlobalProxy">Set the device global proxy
+ to be used while policy is enabled. Only the first device admin
+ sets the effective global proxy.</string>
<!-- The order of these is important, don't reorder without changing Contacts.java --> <skip />
<!-- Phone number types from android.provider.Contacts. This could be used when adding a new phone number for a contact, for example. -->
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index c0ea68d73190..0c3a0e6dde5e 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -33,6 +33,7 @@ import android.app.admin.DevicePolicyManager;
import android.app.admin.IDevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -46,6 +47,8 @@ import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.net.Proxy;
+import android.provider.Settings;
import android.util.Slog;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -58,9 +61,11 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
/**
* Implementation of the device policy APIs.
@@ -105,6 +110,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long maximumTimeToUnlock = 0;
int maximumFailedPasswordsForWipe = 0;
+ // TODO: review implementation decisions with frameworks team
+ boolean specifiesGlobalProxy = false;
+ String globalProxySpec = null;
+ String globalProxyExclusionList = null;
+
ActiveAdmin(DeviceAdminInfo _info) {
info = _info;
}
@@ -171,6 +181,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
out.attribute(null, "value", Integer.toString(maximumFailedPasswordsForWipe));
out.endTag(null, "max-failed-password-wipe");
}
+ if (specifiesGlobalProxy) {
+ out.startTag(null, "specifies-global-proxy");
+ out.attribute(null, "value", Boolean.toString(specifiesGlobalProxy));
+ out.endTag(null, "specifies_global_proxy");
+ if (globalProxySpec != null) {
+ out.startTag(null, "global-proxy-spec");
+ out.attribute(null, "value", globalProxySpec);
+ out.endTag(null, "global-proxy-spec");
+ }
+ if (globalProxyExclusionList != null) {
+ out.startTag(null, "global-proxy-exclusion-list");
+ out.attribute(null, "value", globalProxyExclusionList);
+ out.endTag(null, "global-proxy-exclusion-list");
+ }
+ }
}
void readFromXml(XmlPullParser parser)
@@ -218,6 +243,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if ("max-failed-password-wipe".equals(tag)) {
maximumFailedPasswordsForWipe = Integer.parseInt(
parser.getAttributeValue(null, "value"));
+ } else if ("specifies-global-proxy".equals(tag)) {
+ specifiesGlobalProxy = Boolean.getBoolean(
+ parser.getAttributeValue(null, "value"));
+ } else if ("global-proxy-spec".equals(tag)) {
+ globalProxySpec =
+ parser.getAttributeValue(null, "value");
+ } else if ("global-proxy-exclusion-list".equals(tag)) {
+ globalProxyExclusionList =
+ parser.getAttributeValue(null, "value");
} else {
Slog.w(TAG, "Unknown admin tag: " + tag);
}
@@ -256,6 +290,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
pw.println(maximumTimeToUnlock);
pw.print(prefix); pw.print("maximumFailedPasswordsForWipe=");
pw.println(maximumFailedPasswordsForWipe);
+ pw.print(prefix); pw.print("specifiesGlobalProxy=");
+ pw.println(specifiesGlobalProxy);
+ if (globalProxySpec != null) {
+ pw.print(prefix); pw.print("globalProxySpec=");
+ pw.println(globalProxySpec);
+ }
+ if (globalProxyExclusionList != null) {
+ pw.print(prefix); pw.print("globalProxyEclusionList=");
+ pw.println(globalProxyExclusionList);
+ }
}
}
@@ -370,12 +414,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
void removeActiveAdminLocked(ComponentName adminReceiver) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver);
if (admin != null) {
+ boolean doProxyCleanup =
+ admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
sendAdminCommandLocked(admin,
DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED);
// XXX need to wait for it to complete.
mAdminList.remove(admin);
mAdminMap.remove(adminReceiver);
validatePasswordOwnerLocked();
+ if (doProxyCleanup) {
+ resetGlobalProxy();
+ }
}
}
@@ -1417,6 +1466,94 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ public ComponentName setGlobalProxy(ComponentName who, String proxySpec,
+ String exclusionList) {
+ synchronized(this) {
+ if (who == null) {
+ throw new NullPointerException("ComponentName is null");
+ }
+
+ ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+ DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY);
+
+ // Scan through active admins and find if anyone has already
+ // set the global proxy.
+ final int N = mAdminList.size();
+ Set<ComponentName> compSet = mAdminMap.keySet();
+ for (ComponentName component : compSet) {
+ ActiveAdmin ap = mAdminMap.get(component);
+ if ((ap.specifiesGlobalProxy) && (!component.equals(who))) {
+ // Another admin already sets the global proxy
+ // Return it to the caller.
+ return component;
+ }
+ }
+ if (proxySpec == null) {
+ admin.specifiesGlobalProxy = false;
+ admin.globalProxySpec = null;
+ admin.globalProxyExclusionList = null;
+ } else {
+
+ admin.specifiesGlobalProxy = true;
+ admin.globalProxySpec = proxySpec;
+ admin.globalProxyExclusionList = exclusionList;
+ }
+
+ // Reset the global proxy accordingly
+ // Do this using system permissions, as apps cannot write to secure settings
+ long origId = Binder.clearCallingIdentity();
+ resetGlobalProxy();
+ Binder.restoreCallingIdentity(origId);
+ return null;
+ }
+ }
+
+ public ComponentName getGlobalProxyAdmin() {
+ synchronized(this) {
+ // Scan through active admins and find if anyone has already
+ // set the global proxy.
+ final int N = mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin ap = mAdminList.get(i);
+ if (ap.specifiesGlobalProxy) {
+ // Device admin sets the global proxy
+ // Return it to the caller.
+ return ap.info.getComponent();
+ }
+ }
+ }
+ // No device admin sets the global proxy.
+ return null;
+ }
+
+ private void resetGlobalProxy() {
+ final int N = mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ ActiveAdmin ap = mAdminList.get(i);
+ if (ap.specifiesGlobalProxy) {
+ saveGlobalProxy(ap.globalProxySpec, ap.globalProxyExclusionList);
+ return;
+ }
+ }
+ // No device admins defining global proxies - reset global proxy settings to none
+ saveGlobalProxy(null, null);
+ }
+
+ private void saveGlobalProxy(String proxySpec, String exclusionList) {
+ if (exclusionList == null) {
+ exclusionList = "";
+ }
+ if (proxySpec == null) {
+ proxySpec = "";
+ }
+ // Remove white spaces
+ proxySpec = proxySpec.trim();
+ exclusionList = exclusionList.trim();
+ ContentResolver res = mContext.getContentResolver();
+ Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY, proxySpec);
+ Settings.Secure.putString(res, Settings.Secure.HTTP_PROXY_EXCLUSION_LIST, exclusionList);
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)