summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJim Miller <jaggies@google.com>2014-07-18 19:00:02 -0700
committerJim Miller <jaggies@google.com>2014-07-28 21:32:01 -0700
commit604e7558ef32098644b2f9456d7743a07ae789dc (patch)
treec8e5ec30a280a3a26768a0df8c5f2e75f29e0d32 /services
parent3af1afb0696fac2b3e0dd537048c0e6d11d2df03 (diff)
downloadframeworks_base-604e7558ef32098644b2f9456d7743a07ae789dc.zip
frameworks_base-604e7558ef32098644b2f9456d7743a07ae789dc.tar.gz
frameworks_base-604e7558ef32098644b2f9456d7743a07ae789dc.tar.bz2
Add new DevicePolicyManager API to allow fine-grained TrustAgent management
This adds a new feature that allows a device admin to specify a whitelist of features that are allowed for the given admin. Change-Id: I83f853318efbcf72308532d0a997374f73fa9c10
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/trust/TrustAgentWrapper.java83
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java184
3 files changed, 248 insertions, 21 deletions
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 51009af..0acb82f 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -16,10 +16,14 @@
package com.android.server.trust;
+import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
@@ -30,6 +34,10 @@ import android.util.Log;
import android.util.Slog;
import android.service.trust.ITrustAgentService;
import android.service.trust.ITrustAgentServiceCallback;
+import android.service.trust.TrustAgentService;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* A wrapper around a TrustAgentService interface. Coordinates communication between
@@ -43,6 +51,7 @@ public class TrustAgentWrapper {
private static final int MSG_REVOKE_TRUST = 2;
private static final int MSG_TRUST_TIMEOUT = 3;
private static final int MSG_RESTART_TIMEOUT = 4;
+ private static final int MSG_DPM_CHANGED = 5;
/**
* Time in uptime millis that we wait for the service connection, both when starting
@@ -67,6 +76,7 @@ public class TrustAgentWrapper {
// Trust state
private boolean mTrusted;
private CharSequence mMessage;
+ private boolean mTrustDisabledByDpm;
private final Handler mHandler = new Handler() {
@Override
@@ -109,6 +119,9 @@ public class TrustAgentWrapper {
unbind();
mTrustManagerService.resetAgent(mName, mUserId);
break;
+ case MSG_DPM_CHANGED:
+ updateDevicePolicyFeatures(mName);
+ break;
}
}
};
@@ -141,6 +154,8 @@ public class TrustAgentWrapper {
mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
setCallback(mCallback);
+ updateDevicePolicyFeatures(name);
+ watchForDpmChanges(true);
}
@Override
@@ -152,9 +167,21 @@ public class TrustAgentWrapper {
if (mBound) {
scheduleRestart();
}
+ // mTrustDisabledByDpm maintains state
+ watchForDpmChanges(false);
}
};
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
+ .equals(intent.getAction())) {
+ mHandler.sendEmptyMessage(MSG_DPM_CHANGED);
+ }
+ }
+ };
public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
Intent intent, UserHandle user) {
@@ -196,8 +223,62 @@ public class TrustAgentWrapper {
}
}
+ private void watchForDpmChanges(boolean start) {
+ if (start) {
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ } else {
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ }
+ }
+
+ private boolean updateDevicePolicyFeatures(ComponentName name) {
+ boolean trustDisabled = false;
+ if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + name + ")");
+ try {
+ if (mTrustAgentService != null) {
+ DevicePolicyManager dpm =
+ (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ if (dpm != null) {
+ // If trust disabled, only enable it if the options bundle is set and
+ // accepted by the TrustAgent.
+ if ((dpm.getKeyguardDisabledFeatures(null)
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
+ List<String> features = dpm.getTrustAgentFeaturesEnabled(null, name);
+ if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " + features);
+ if (features != null && features.size() > 0) {
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(TrustAgentService.KEY_FEATURES,
+ (ArrayList<String>)features);
+ if (DEBUG) {
+ Slog.v(TAG, "TrustAgent " + name.flattenToShortString()
+ + " disabled except "+ features);
+ }
+ trustDisabled = mTrustAgentService.setTrustAgentFeaturesEnabled(bundle);
+ } else {
+ if (DEBUG) Slog.v(TAG, "TrustAgent " + name + " disabled by flag");
+ trustDisabled = true; // trust agent should be disabled
+ }
+ }
+ } else {
+ Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
+ new IllegalStateException("Stack trace:"));
+ }
+ }
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ if (mTrustDisabledByDpm != trustDisabled) {
+ mTrustDisabledByDpm = trustDisabled;
+ mTrustManagerService.updateTrust(mUserId);
+ }
+ return trustDisabled;
+ }
+
public boolean isTrusted() {
- return mTrusted;
+ return mTrusted && !mTrustDisabledByDpm;
}
public CharSequence getMessage() {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 14436aa..9c2df55 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -169,7 +169,7 @@ public class TrustManagerService extends SystemService {
for (UserInfo userInfo : userInfos) {
int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
.getKeyguardDisabledFeatures(null, userInfo.id);
- boolean disableTrustAgents =
+ final boolean disableTrustAgents =
(disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 25f9e9b..f49451e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -80,6 +80,7 @@ import android.security.Credentials;
import android.security.IKeyChainService;
import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection;
+import android.service.trust.TrustAgentService;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -89,6 +90,11 @@ import android.util.Xml;
import android.view.IWindowManager;
import org.xmlpull.v1.XmlPullParser;
+
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.TEXT;
+
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -111,6 +117,8 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
/**
@@ -260,6 +268,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
private static final String TAG_ACCOUNT_TYPE = "account-type";
private static final String TAG_ENCRYPTION_REQUESTED = "encryption-requested";
+ private static final String TAG_MANAGE_TRUST_AGENT_FEATURES = "manage-trust-agent-features";
+ private static final String TAG_TRUST_AGENT_FEATURE = "feature";
+ private static final String TAG_TRUST_AGENT_COMPONENT = "component";
private static final String TAG_PASSWORD_EXPIRATION_DATE = "password-expiration-date";
private static final String TAG_PASSWORD_EXPIRATION_TIMEOUT = "password-expiration-timeout";
private static final String TAG_GLOBAL_PROXY_EXCLUSION_LIST = "global-proxy-exclusion-list";
@@ -333,6 +344,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean specifiesGlobalProxy = false;
String globalProxySpec = null;
String globalProxyExclusionList = null;
+ HashMap<String, List<String>> trustAgentFeatures = new HashMap<String, List<String>>();
ActiveAdmin(DeviceAdminInfo _info) {
info = _info;
@@ -463,15 +475,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
out.endTag(null, TAG_DISABLE_ACCOUNT_MANAGEMENT);
}
+ if (!trustAgentFeatures.isEmpty()) {
+ Set<Entry<String, List<String>>> set = trustAgentFeatures.entrySet();
+ out.startTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES);
+ for (Entry<String, List<String>> component : set) {
+ out.startTag(null, TAG_TRUST_AGENT_COMPONENT);
+ out.attribute(null, ATTR_VALUE, component.getKey());
+ for (String feature : component.getValue()) {
+ out.startTag(null, TAG_TRUST_AGENT_FEATURE);
+ out.attribute(null, ATTR_VALUE, feature);
+ out.endTag(null, TAG_TRUST_AGENT_FEATURE);
+ }
+ out.endTag(null, TAG_TRUST_AGENT_COMPONENT);
+ }
+ out.endTag(null, TAG_MANAGE_TRUST_AGENT_FEATURES);
+ }
}
void readFromXml(XmlPullParser parser)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
- while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
- && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
- if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ while ((type=parser.next()) != END_DOCUMENT
+ && (type != END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == END_TAG || type == TEXT) {
continue;
}
String tag = parser.getName();
@@ -541,22 +568,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_DISABLE_ACCOUNT_MANAGEMENT.equals(tag)) {
- int outerDepthDAM = parser.getDepth();
- int typeDAM;
- while ((typeDAM=parser.next()) != XmlPullParser.END_DOCUMENT
- && (typeDAM != XmlPullParser.END_TAG
- || parser.getDepth() > outerDepthDAM)) {
- if (typeDAM == XmlPullParser.END_TAG || typeDAM == XmlPullParser.TEXT) {
- continue;
- }
- String tagDAM = parser.getName();
- if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
- accountTypesWithManagementDisabled.add(
- parser.getAttributeValue(null, ATTR_VALUE));
- } else {
- Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
- }
- }
+ accountTypesWithManagementDisabled = readDisableAccountInfo(parser, tag);
+ } else if (TAG_MANAGE_TRUST_AGENT_FEATURES.equals(tag)) {
+ trustAgentFeatures = getAllTrustAgentFeatures(parser, tag);
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
}
@@ -564,6 +578,68 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ private Set<String> readDisableAccountInfo(XmlPullParser parser, String tag)
+ throws XmlPullParserException, IOException {
+ int outerDepthDAM = parser.getDepth();
+ int typeDAM;
+ Set<String> result = new HashSet<String>();
+ while ((typeDAM=parser.next()) != END_DOCUMENT
+ && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) {
+ if (typeDAM == END_TAG || typeDAM == TEXT) {
+ continue;
+ }
+ String tagDAM = parser.getName();
+ if (TAG_ACCOUNT_TYPE.equals(tagDAM)) {
+ result.add(parser.getAttributeValue(null, ATTR_VALUE));
+ } else {
+ Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
+ }
+ }
+ return result;
+ }
+
+ private HashMap<String, List<String>> getAllTrustAgentFeatures(XmlPullParser parser,
+ String tag) throws XmlPullParserException, IOException {
+ int outerDepthDAM = parser.getDepth();
+ int typeDAM;
+ HashMap<String, List<String>> result = new HashMap<String, List<String>>();
+ while ((typeDAM=parser.next()) != END_DOCUMENT
+ && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) {
+ if (typeDAM == END_TAG || typeDAM == TEXT) {
+ continue;
+ }
+ String tagDAM = parser.getName();
+ if (TAG_TRUST_AGENT_COMPONENT.equals(tagDAM)) {
+ final String component = parser.getAttributeValue(null, ATTR_VALUE);
+ result.put(component, getTrustAgentFeatures(parser, tag));
+ } else {
+ Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
+ }
+ }
+ return result;
+ }
+
+ private List<String> getTrustAgentFeatures(XmlPullParser parser, String tag)
+ throws XmlPullParserException, IOException {
+ int outerDepthDAM = parser.getDepth();
+ int typeDAM;
+ ArrayList<String> result = new ArrayList<String>();
+ while ((typeDAM=parser.next()) != END_DOCUMENT
+ && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) {
+ if (typeDAM == END_TAG || typeDAM == TEXT) {
+ continue;
+ }
+ String tagDAM = parser.getName();
+ if (TAG_TRUST_AGENT_FEATURE.equals(tagDAM)) {
+ final String feature = parser.getAttributeValue(null, ATTR_VALUE);
+ result.add(feature);
+ } else {
+ Slog.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM);
+ }
+ }
+ return result;
+ }
+
void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("uid="); pw.println(getUid());
pw.print(prefix); pw.println("policies:");
@@ -3533,6 +3609,76 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ public void setTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent,
+ List<String>features, int userHandle) {
+ if (!mHasFeature) {
+ return;
+ }
+ enforceCrossUserPermission(userHandle);
+ enforceNotManagedProfile(userHandle, "manage trust agent features");
+ synchronized (this) {
+ if (admin == null) {
+ throw new NullPointerException("admin is null");
+ }
+ if (agent == null) {
+ throw new NullPointerException("agent is null");
+ }
+ ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
+ DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
+ ap.trustAgentFeatures.put(agent.flattenToString(), features);
+ saveSettingsLocked(userHandle);
+ syncDeviceCapabilitiesLocked(getUserData(userHandle));
+ }
+ }
+
+ public List<String> getTrustAgentFeaturesEnabled(ComponentName admin, ComponentName agent,
+ int userHandle) {
+ if (!mHasFeature) {
+ return null;
+ }
+ enforceCrossUserPermission(userHandle);
+ synchronized (this) {
+ if (agent == null) {
+ throw new NullPointerException("agent is null");
+ }
+ final String componentName = agent.flattenToString();
+ if (admin != null) {
+ final ActiveAdmin ap = getActiveAdminUncheckedLocked(admin, userHandle);
+ return (ap != null) ? ap.trustAgentFeatures.get(componentName) : null;
+ }
+
+ // Return strictest policy for this user and profiles that are visible from this user.
+ List<UserInfo> profiles = mUserManager.getProfiles(userHandle);
+ List<String> result = null;
+ for (UserInfo userInfo : profiles) {
+ DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier());
+ final int N = policy.mAdminList.size();
+ for (int i=0; i<N; i++) {
+ ActiveAdmin ap = policy.mAdminList.get(i);
+ // Compute the intersection of all features for active admins that disable
+ // trust agents:
+ if ((ap.disabledKeyguardFeatures
+ & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
+ final List<String> features = ap.trustAgentFeatures.get(componentName);
+ if (result == null) {
+ if (features == null || features.size() == 0) {
+ result = new ArrayList<String>();
+ Slog.w(LOG_TAG, "admin " + ap.info.getPackageName()
+ + " has null trust agent feature set; all will be disabled");
+ } else {
+ result = new ArrayList<String>(features.size());
+ result.addAll(features);
+ }
+ } else {
+ result.retainAll(features);
+ }
+ }
+ }
+ }
+ return result;
+ }
+ }
+
@Override
public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
synchronized (this) {