diff options
21 files changed, 550 insertions, 118 deletions
diff --git a/api/current.txt b/api/current.txt index d1ece22a5d09..a261bd6a5fd0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8582,6 +8582,7 @@ package android.content.pm { public class LauncherApps { method public void addOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback); + method public void addOnAppsChangedCallback(android.content.pm.LauncherApps.OnAppsChangedCallback, android.os.Handler); method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle); method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle); method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle); diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 5782edc3e498..983e347f50d8 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1708,6 +1708,9 @@ public class Notification implements Parcelable if (headsUpContentView != null) { headsUpContentView.setUser(user); } + if (publicVersion != null) { + publicVersion.setUser(user); + } } /** diff --git a/core/java/android/app/trust/ITrustListener.aidl b/core/java/android/app/trust/ITrustListener.aidl index 46800438f490..45a066dfdf92 100644 --- a/core/java/android/app/trust/ITrustListener.aidl +++ b/core/java/android/app/trust/ITrustListener.aidl @@ -23,4 +23,5 @@ package android.app.trust; */ oneway interface ITrustListener { void onTrustChanged(boolean enabled, int userId); + void onTrustManagedChanged(boolean managed, int userId); }
\ No newline at end of file diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 6e90590385be..796e3cc3498e 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -31,6 +31,7 @@ import android.util.Log; public class TrustManager { private static final int MSG_TRUST_CHANGED = 1; + private static final int MSG_TRUST_MANAGED_CHANGED = 2; private static final String TAG = "TrustManager"; @@ -98,6 +99,13 @@ public class TrustManager { mHandler.obtainMessage(MSG_TRUST_CHANGED, (enabled ? 1 : 0), userId, trustListener).sendToTarget(); } + + @Override + public void onTrustManagedChanged(boolean managed, int userId) + throws RemoteException { + mHandler.obtainMessage(MSG_TRUST_MANAGED_CHANGED, (managed ? 1 : 0), userId, + trustListener).sendToTarget(); + } }; mService.registerTrustListener(iTrustListener); mTrustListeners.put(trustListener, iTrustListener); @@ -133,6 +141,8 @@ public class TrustManager { case MSG_TRUST_CHANGED: ((TrustListener)msg.obj).onTrustChanged(msg.arg1 != 0, msg.arg2); break; + case MSG_TRUST_MANAGED_CHANGED: + ((TrustListener)msg.obj).onTrustManagedChanged(msg.arg1 != 0, msg.arg2); } } }; @@ -145,5 +155,12 @@ public class TrustManager { * @param userId the user, for which the trust changed. */ void onTrustChanged(boolean enabled, int userId); + + /** + * Reports that whether trust is managed has changed + * @param enabled if true, at least one trust agent is managing trust. + * @param userId the user, for which the state changed. + */ + void onTrustManagedChanged(boolean enabled, int userId); } } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index c95a5bf5c780..8c37e9e790b4 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -25,6 +25,9 @@ import android.content.pm.IOnAppsChangedListener; import android.content.pm.PackageManager.NameNotFoundException; import android.graphics.Rect; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; @@ -55,8 +58,8 @@ public class LauncherApps { private ILauncherApps mService; private PackageManager mPm; - private List<OnAppsChangedCallback> mCallbacks - = new ArrayList<OnAppsChangedCallback>(); + private List<CallbackMessageHandler> mCallbacks + = new ArrayList<CallbackMessageHandler>(); /** * Callbacks for package changes to this and related managed profiles. @@ -65,6 +68,9 @@ public class LauncherApps { /** * Indicates that a package was removed from the specified profile. * + * If a package is removed while being updated onPackageChanged will be + * called instead. + * * @param packageName The name of the package that was removed. * @param user The UserHandle of the profile that generated the change. */ @@ -73,6 +79,9 @@ public class LauncherApps { /** * Indicates that a package was added to the specified profile. * + * If a package is added while being updated then onPackageChanged will be + * called instead. + * * @param packageName The name of the package that was added. * @param user The UserHandle of the profile that generated the change. */ @@ -80,6 +89,8 @@ public class LauncherApps { /** * Indicates that a package was modified in the specified profile. + * This can happen, for example, when the package is updated or when + * one or more components are enabled or disabled. * * @param packageName The name of the package that has changed. * @param user The UserHandle of the profile that generated the change. @@ -286,10 +297,21 @@ public class LauncherApps { * @param callback The callback to add. */ public void addOnAppsChangedCallback(OnAppsChangedCallback callback) { + addOnAppsChangedCallback(callback, null); + } + + /** + * Adds a callback for changes to packages in current and managed profiles. + * + * @param callback The callback to add. + * @param handler that should be used to post callbacks on, may be null. + */ + public void addOnAppsChangedCallback(OnAppsChangedCallback callback, Handler handler) { synchronized (this) { if (callback != null && !mCallbacks.contains(callback)) { - mCallbacks.add(callback); - if (mCallbacks.size() == 1) { + boolean addedFirstCallback = mCallbacks.size() == 0; + addCallbackLocked(callback, handler); + if (addedFirstCallback) { try { mService.addOnAppsChangedListener(mAppsChangedListener); } catch (RemoteException re) { @@ -307,7 +329,7 @@ public class LauncherApps { */ public void removeOnAppsChangedCallback(OnAppsChangedCallback callback) { synchronized (this) { - mCallbacks.remove(callback); + removeCallbackLocked(callback); if (mCallbacks.size() == 0) { try { mService.removeOnAppsChangedListener(mAppsChangedListener); @@ -317,16 +339,40 @@ public class LauncherApps { } } + private void removeCallbackLocked(OnAppsChangedCallback callback) { + if (callback == null) { + throw new IllegalArgumentException("Callback cannot be null"); + } + final int size = mCallbacks.size(); + for (int i = 0; i < size; ++i) { + if (mCallbacks.get(i).mCallback == callback) { + mCallbacks.remove(i); + return; + } + } + } + + private void addCallbackLocked(OnAppsChangedCallback callback, Handler handler) { + // Remove if already present. + removeCallbackLocked(callback); + if (handler == null) { + handler = new Handler(); + } + CallbackMessageHandler toAdd = new CallbackMessageHandler(handler.getLooper(), callback); + mCallbacks.add(toAdd); + } + private IOnAppsChangedListener.Stub mAppsChangedListener = new IOnAppsChangedListener.Stub() { @Override - public void onPackageRemoved(UserHandle user, String packageName) throws RemoteException { + public void onPackageRemoved(UserHandle user, String packageName) + throws RemoteException { if (DEBUG) { Log.d(TAG, "onPackageRemoved " + user.getIdentifier() + "," + packageName); } synchronized (LauncherApps.this) { - for (OnAppsChangedCallback callback : mCallbacks) { - callback.onPackageRemoved(packageName, user); + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnPackageRemoved(packageName, user); } } } @@ -337,8 +383,8 @@ public class LauncherApps { Log.d(TAG, "onPackageChanged " + user.getIdentifier() + "," + packageName); } synchronized (LauncherApps.this) { - for (OnAppsChangedCallback callback : mCallbacks) { - callback.onPackageChanged(packageName, user); + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnPackageChanged(packageName, user); } } } @@ -349,8 +395,8 @@ public class LauncherApps { Log.d(TAG, "onPackageAdded " + user.getIdentifier() + "," + packageName); } synchronized (LauncherApps.this) { - for (OnAppsChangedCallback callback : mCallbacks) { - callback.onPackageAdded(packageName, user); + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnPackageAdded(packageName, user); } } } @@ -362,8 +408,8 @@ public class LauncherApps { Log.d(TAG, "onPackagesAvailable " + user.getIdentifier() + "," + packageNames); } synchronized (LauncherApps.this) { - for (OnAppsChangedCallback callback : mCallbacks) { - callback.onPackagesAvailable(packageNames, user, replacing); + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnPackagesAvailable(packageNames, user, replacing); } } } @@ -375,10 +421,96 @@ public class LauncherApps { Log.d(TAG, "onPackagesUnavailable " + user.getIdentifier() + "," + packageNames); } synchronized (LauncherApps.this) { - for (OnAppsChangedCallback callback : mCallbacks) { - callback.onPackagesUnavailable(packageNames, user, replacing); + for (CallbackMessageHandler callback : mCallbacks) { + callback.postOnPackagesUnavailable(packageNames, user, replacing); } } } }; + + private static class CallbackMessageHandler extends Handler { + private static final int MSG_ADDED = 1; + private static final int MSG_REMOVED = 2; + private static final int MSG_CHANGED = 3; + private static final int MSG_AVAILABLE = 4; + private static final int MSG_UNAVAILABLE = 5; + + private OnAppsChangedCallback mCallback; + + private static class CallbackInfo { + String[] packageNames; + String packageName; + boolean replacing; + UserHandle user; + } + + public CallbackMessageHandler(Looper looper, OnAppsChangedCallback callback) { + super(looper, null, true); + mCallback = callback; + } + + @Override + public void handleMessage(Message msg) { + if (mCallback == null || !(msg.obj instanceof CallbackInfo)) { + return; + } + CallbackInfo info = (CallbackInfo) msg.obj; + switch (msg.what) { + case MSG_ADDED: + mCallback.onPackageAdded(info.packageName, info.user); + break; + case MSG_REMOVED: + mCallback.onPackageRemoved(info.packageName, info.user); + break; + case MSG_CHANGED: + mCallback.onPackageChanged(info.packageName, info.user); + break; + case MSG_AVAILABLE: + mCallback.onPackagesAvailable(info.packageNames, info.user, info.replacing); + break; + case MSG_UNAVAILABLE: + mCallback.onPackagesUnavailable(info.packageNames, info.user, info.replacing); + break; + } + } + + public void postOnPackageAdded(String packageName, UserHandle user) { + CallbackInfo info = new CallbackInfo(); + info.packageName = packageName; + info.user = user; + obtainMessage(MSG_ADDED, info).sendToTarget(); + } + + public void postOnPackageRemoved(String packageName, UserHandle user) { + CallbackInfo info = new CallbackInfo(); + info.packageName = packageName; + info.user = user; + obtainMessage(MSG_REMOVED, info).sendToTarget(); + } + + public void postOnPackageChanged(String packageName, UserHandle user) { + CallbackInfo info = new CallbackInfo(); + info.packageName = packageName; + info.user = user; + obtainMessage(MSG_CHANGED, info).sendToTarget(); + } + + public void postOnPackagesAvailable(String[] packageNames, UserHandle user, + boolean replacing) { + CallbackInfo info = new CallbackInfo(); + info.packageNames = packageNames; + info.replacing = replacing; + info.user = user; + obtainMessage(MSG_AVAILABLE, info).sendToTarget(); + } + + public void postOnPackagesUnavailable(String[] packageNames, UserHandle user, + boolean replacing) { + CallbackInfo info = new CallbackInfo(); + info.packageNames = packageNames; + info.replacing = replacing; + info.user = user; + obtainMessage(MSG_UNAVAILABLE, info).sendToTarget(); + } + } } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index b5c4cd61a933..b0e0b4972a58 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -96,8 +96,7 @@ public class Build { * * See {@link #SUPPORTED_32_BIT_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. */ - public static final String[] SUPPORTED_ABIS = SystemProperties.get("ro.product.cpu.abilist") - .split(","); + public static final String[] SUPPORTED_ABIS = getStringList("ro.product.cpu.abilist", ","); /** * An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI @@ -106,7 +105,7 @@ public class Build { * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}. */ public static final String[] SUPPORTED_32_BIT_ABIS = - SystemProperties.get("ro.product.cpu.abilist32").split(","); + getStringList("ro.product.cpu.abilist32", ","); /** * An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI @@ -115,7 +114,7 @@ public class Build { * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_32_BIT_ABIS}. */ public static final String[] SUPPORTED_64_BIT_ABIS = - SystemProperties.get("ro.product.cpu.abilist64").split(","); + getStringList("ro.product.cpu.abilist64", ","); /** Various version strings. */ @@ -155,7 +154,7 @@ public class Build { public static final String CODENAME = getString("ro.build.version.codename"); private static final String[] ALL_CODENAMES - = getString("ro.build.version.all_codenames").split(","); + = getStringList("ro.build.version.all_codenames", ","); /** * @hide @@ -614,6 +613,15 @@ public class Build { return SystemProperties.get(property, UNKNOWN); } + private static String[] getStringList(String property, String separator) { + String value = SystemProperties.get(property); + if (value.isEmpty()) { + return new String[0]; + } else { + return value.split(separator); + } + } + private static long getLong(String property) { try { return Long.parseLong(SystemProperties.get(property)); diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 1fc64e4d3e81..7c8624c5ffbe 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -29,8 +29,11 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; +import java.util.Collections; import java.util.List; /** @@ -540,6 +543,8 @@ public abstract class NotificationListenerService extends Service { */ public static class RankingMap implements Parcelable { private final NotificationRankingUpdate mRankingUpdate; + private ArrayMap<String,Integer> mRanks; + private ArraySet<Object> mIntercepted; private RankingMap(NotificationRankingUpdate rankingUpdate) { mRankingUpdate = rankingUpdate; @@ -569,14 +574,13 @@ public abstract class NotificationListenerService extends Service { } private int getRank(String key) { - // TODO: Optimize. - String[] orderedKeys = mRankingUpdate.getOrderedKeys(); - for (int i = 0; i < orderedKeys.length; i++) { - if (orderedKeys[i].equals(key)) { - return i; + synchronized (this) { + if (mRanks == null) { + buildRanksLocked(); } } - return -1; + Integer rank = mRanks.get(key); + return rank != null ? rank : -1; } private boolean isAmbient(String key) { @@ -585,13 +589,29 @@ public abstract class NotificationListenerService extends Service { } private boolean isIntercepted(String key) { - // TODO: Optimize. - for (String interceptedKey : mRankingUpdate.getInterceptedKeys()) { - if (interceptedKey.equals(key)) { - return true; + synchronized (this) { + if (mIntercepted == null) { + buildInterceptedSetLocked(); } } - return false; + return mIntercepted.contains(key); + } + + // Locked by 'this' + private void buildRanksLocked() { + String[] orderedKeys = mRankingUpdate.getOrderedKeys(); + mRanks = new ArrayMap<>(orderedKeys.length); + for (int i = 0; i < orderedKeys.length; i++) { + String key = orderedKeys[i]; + mRanks.put(key, i); + } + } + + // Locked by 'this' + private void buildInterceptedSetLocked() { + String[] dndInterceptedKeys = mRankingUpdate.getInterceptedKeys(); + mIntercepted = new ArraySet<>(dndInterceptedKeys.length); + Collections.addAll(mIntercepted, dndInterceptedKeys); } // ----------- Parcelable diff --git a/core/java/android/service/trust/ITrustAgentService.aidl b/core/java/android/service/trust/ITrustAgentService.aidl index 49eb7bea4061..637d08070619 100644 --- a/core/java/android/service/trust/ITrustAgentService.aidl +++ b/core/java/android/service/trust/ITrustAgentService.aidl @@ -25,5 +25,5 @@ import android.service.trust.ITrustAgentServiceCallback; interface ITrustAgentService { oneway void onUnlockAttempt(boolean successful); oneway void setCallback(ITrustAgentServiceCallback callback); - boolean setTrustAgentFeaturesEnabled(in Bundle options); + oneway void setTrustAgentFeaturesEnabled(in Bundle options, IBinder token); } diff --git a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl index 9e4c2bf940fa..b107bccb4f84 100644 --- a/core/java/android/service/trust/ITrustAgentServiceCallback.aidl +++ b/core/java/android/service/trust/ITrustAgentServiceCallback.aidl @@ -16,6 +16,7 @@ package android.service.trust; import android.os.Bundle; +import android.os.IBinder; import android.os.UserHandle; /** @@ -25,4 +26,6 @@ import android.os.UserHandle; oneway interface ITrustAgentServiceCallback { void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser); void revokeTrust(); + void setManagingTrust(boolean managingTrust); + void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token); } diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java index 61da85f613dd..51f07ecf16bb 100644 --- a/core/java/android/service/trust/TrustAgentService.java +++ b/core/java/android/service/trust/TrustAgentService.java @@ -28,6 +28,7 @@ import android.content.pm.ServiceInfo; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.RemoteException; import android.util.Log; import android.util.Slog; @@ -66,6 +67,13 @@ import android.util.Slog; public class TrustAgentService extends Service { private final String TAG = TrustAgentService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]"; + private static final boolean DEBUG = false; + + // Temporary workaround to allow current trust agent implementations to continue working. + // This and the code guarded by this should be removed before shipping. + // If true, calls setManagingTrust(true) after onCreate, if it wasn't already set. + // TODO: Remove this once all agents are updated. + private static final boolean SET_MANAGED_FOR_LEGACY_AGENTS = true; /** * The {@link Intent} that must be declared as handled by the service. @@ -87,13 +95,14 @@ public class TrustAgentService extends Service { public static final String KEY_FEATURES = "trust_agent_features"; private static final int MSG_UNLOCK_ATTEMPT = 1; - - private static final boolean DEBUG = false; + private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2; private ITrustAgentServiceCallback mCallback; private Runnable mPendingGrantTrustTask; + private boolean mManagingTrust; + // Lock used to access mPendingGrantTrustTask and mCallback. private final Object mLock = new Object(); @@ -103,12 +112,29 @@ public class TrustAgentService extends Service { case MSG_UNLOCK_ATTEMPT: onUnlockAttempt(msg.arg1 != 0); break; + case MSG_SET_TRUST_AGENT_FEATURES_ENABLED: + Bundle features = msg.peekData(); + IBinder token = (IBinder) msg.obj; + boolean result = onSetTrustAgentFeaturesEnabled(features); + try { + synchronized (mLock) { + mCallback.onSetTrustAgentFeaturesEnabledCompleted(result, token); + } + } catch (RemoteException e) { + onError("calling onSetTrustAgentFeaturesEnabledCompleted()"); + } + break; } - }; + } }; @Override public void onCreate() { + // TODO: Remove this once all agents are updated. + if (SET_MANAGED_FOR_LEGACY_AGENTS) { + setManagingTrust(true); + } + super.onCreate(); ComponentName component = new ComponentName(this, getClass()); try { @@ -163,10 +189,15 @@ public class TrustAgentService extends Service { * for this agent will automatically be revoked when the timeout expires. * @param initiatedByUser indicates that the user has explicitly initiated an action that proves * the user is about to use the device. + * @throws IllegalStateException if the agent is not currently managing trust. */ public final void grantTrust( final CharSequence message, final long durationMs, final boolean initiatedByUser) { synchronized (mLock) { + if (!mManagingTrust) { + throw new IllegalStateException("Cannot grant trust if agent is not managing trust." + + " Call setManagingTrust(true) first."); + } if (mCallback != null) { try { mCallback.grantTrust(message.toString(), durationMs, initiatedByUser); @@ -204,6 +235,29 @@ public class TrustAgentService extends Service { } } + /** + * Call to notify the system if the agent is ready to manage trust. + * + * This property is not persistent across recreating the service and defaults to false. + * Therefore this method is typically called when initializing the agent in {@link #onCreate}. + * + * @param managingTrust indicates if the agent would like to manage trust. + */ + public final void setManagingTrust(boolean managingTrust) { + synchronized (mLock) { + if (mManagingTrust != managingTrust) { + mManagingTrust = managingTrust; + if (mCallback != null) { + try { + mCallback.setManagingTrust(managingTrust); + } catch (RemoteException e) { + onError("calling setManagingTrust()"); + } + } + } + } + } + @Override public final IBinder onBind(Intent intent) { if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent); @@ -221,6 +275,15 @@ public class TrustAgentService extends Service { public void setCallback(ITrustAgentServiceCallback callback) { synchronized (mLock) { mCallback = callback; + // The managingTrust property is false implicitly on the server-side, so we only + // need to set it here if the agent has decided to manage trust. + if (mManagingTrust) { + try { + mCallback.setManagingTrust(mManagingTrust); + } catch (RemoteException e ) { + onError("calling setManagingTrust()"); + } + } if (mPendingGrantTrustTask != null) { mPendingGrantTrustTask.run(); mPendingGrantTrustTask = null; @@ -229,10 +292,10 @@ public class TrustAgentService extends Service { } @Override - public boolean setTrustAgentFeaturesEnabled(Bundle features) { - synchronized (mLock) { - return onSetTrustAgentFeaturesEnabled(features); - } + public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) { + Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token); + msg.setData(features); + msg.sendToTarget(); } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index f0f5772acccd..e4d78507c0d4 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -216,6 +216,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { }; private SparseBooleanArray mUserHasTrust = new SparseBooleanArray(); + private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray(); private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray(); @Override @@ -230,6 +231,18 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + @Override + public void onTrustManagedChanged(boolean managed, int userId) { + mUserTrustIsManaged.put(userId, managed); + + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onTrustManagedChanged(userId); + } + } + } + private void onFingerprintRecognized(int userId) { mUserFingerprintRecognized.put(userId, true); for (int i = 0; i < mCallbacks.size(); i++) { @@ -305,6 +318,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { || mUserFingerprintRecognized.get(userId); } + public boolean getUserTrustIsManaged(int userId) { + return mUserTrustIsManaged.get(userId) && !isTrustDisabled(userId); + } + static class DisplayClientState { public int clientGeneration; public boolean clearing; diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 14c127835868..0aefa2d6d7ce 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -174,6 +174,11 @@ public class KeyguardUpdateMonitorCallback { public void onTrustChanged(int userId) { } /** + * Called when trust being managed changes for a user. + */ + public void onTrustManagedChanged(int userId) { } + + /** * Called when a fingerprint is recognized. * @param userId */ @@ -183,5 +188,4 @@ public class KeyguardUpdateMonitorCallback { * Called when fingerprint is acquired but not yet recognized */ public void onFingerprintAcquired(int info) { } - } diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml index 06a06bf876b0..796cefbe68c3 100644 --- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml +++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml @@ -32,8 +32,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Crash" /> + <CheckBox android:id="@+id/managing_trust" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:text="Managing trust" /> <CheckBox android:id="@+id/report_unlock_attempts" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" android:text="Report unlock attempts" /> </LinearLayout>
\ No newline at end of file diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java index 50a3f822410e..ed17494a7fce 100644 --- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java +++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgent.java @@ -28,7 +28,8 @@ import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.widget.Toast; -public class SampleTrustAgent extends TrustAgentService { +public class SampleTrustAgent extends TrustAgentService + implements SharedPreferences.OnSharedPreferenceChangeListener { LocalBroadcastManager mLocalBroadcastManager; @@ -41,6 +42,8 @@ public class SampleTrustAgent extends TrustAgentService { private static final String PREFERENCE_REPORT_UNLOCK_ATTEMPTS = "preference.report_unlock_attempts"; + private static final String PREFERENCE_MANAGING_TRUST + = "preference.managing_trust"; private static final String TAG = "SampleTrustAgent"; @@ -52,6 +55,9 @@ public class SampleTrustAgent extends TrustAgentService { filter.addAction(ACTION_REVOKE_TRUST); mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); mLocalBroadcastManager.registerReceiver(mReceiver, filter); + setManagingTrust(getIsManagingTrust(this)); + PreferenceManager.getDefaultSharedPreferences(this) + .registerOnSharedPreferenceChangeListener(this); } @Override @@ -73,6 +79,8 @@ public class SampleTrustAgent extends TrustAgentService { public void onDestroy() { super.onDestroy(); mLocalBroadcastManager.unregisterReceiver(mReceiver); + PreferenceManager.getDefaultSharedPreferences(this) + .unregisterOnSharedPreferenceChangeListener(this); } private BroadcastReceiver mReceiver = new BroadcastReceiver() { @@ -80,9 +88,14 @@ public class SampleTrustAgent extends TrustAgentService { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_GRANT_TRUST.equals(action)) { - grantTrust(intent.getStringExtra(EXTRA_MESSAGE), - intent.getLongExtra(EXTRA_DURATION, 0), - false /* initiatedByUser */); + try { + grantTrust(intent.getStringExtra(EXTRA_MESSAGE), + intent.getLongExtra(EXTRA_DURATION, 0), + false /* initiatedByUser */); + } catch (IllegalStateException e) { + Toast.makeText(context, + "IllegalStateException: " + e.getMessage(), Toast.LENGTH_SHORT).show(); + } } else if (ACTION_REVOKE_TRUST.equals(action)) { revokeTrust(); } @@ -114,4 +127,23 @@ public class SampleTrustAgent extends TrustAgentService { .getDefaultSharedPreferences(context); return sharedPreferences.getBoolean(PREFERENCE_REPORT_UNLOCK_ATTEMPTS, false); } + + public static void setIsManagingTrust(Context context, boolean enabled) { + SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(context); + sharedPreferences.edit().putBoolean(PREFERENCE_MANAGING_TRUST, enabled).apply(); + } + + public static boolean getIsManagingTrust(Context context) { + SharedPreferences sharedPreferences = PreferenceManager + .getDefaultSharedPreferences(context); + return sharedPreferences.getBoolean(PREFERENCE_MANAGING_TRUST, false); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (PREFERENCE_MANAGING_TRUST.equals(key)) { + setManagingTrust(getIsManagingTrust(this)); + } + } } diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java index 6b5f78b52ac2..2c856099c708 100644 --- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java +++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java @@ -29,6 +29,7 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi private static final int TRUST_DURATION_MS = 30 * 1000; private CheckBox mReportUnlockAttempts; + private CheckBox mManagingTrust; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -41,12 +42,16 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts); mReportUnlockAttempts.setOnCheckedChangeListener(this); + + mManagingTrust = (CheckBox) findViewById(R.id.managing_trust); + mManagingTrust.setOnCheckedChangeListener(this); } @Override protected void onResume() { super.onResume(); mReportUnlockAttempts.setChecked(SampleTrustAgent.getReportUnlockAttempts(this)); + mManagingTrust.setChecked(SampleTrustAgent.getIsManagingTrust(this)); } @Override @@ -64,8 +69,10 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (buttonView.getId() == R.id.report_unlock_attempts) { + if (buttonView == mReportUnlockAttempts) { SampleTrustAgent.setReportUnlockAttempts(this, isChecked); + } else if (buttonView == mManagingTrust) { + SampleTrustAgent.setIsManagingTrust(this, isChecked); } } } diff --git a/packages/SystemUI/res/drawable/trust_circle.xml b/packages/SystemUI/res/drawable/trust_circle.xml new file mode 100644 index 000000000000..89f4a0b89e5a --- /dev/null +++ b/packages/SystemUI/res/drawable/trust_circle.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="ring" + android:innerRadius="24dp" android:thickness="1dp"> + <solid android:color="#66ffffff" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index b5f517d25beb..82e59c0249ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -237,6 +237,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL ? R.drawable.ic_lock_open_24dp : R.drawable.ic_lock_24dp; mLockIcon.setImageResource(iconRes); + boolean trustManaged = mUnlockMethodCache.isTrustManaged(); + mLockIcon.setBackgroundResource(trustManaged ? R.drawable.trust_circle : 0); } public KeyguardAffordanceView getPhoneView() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java index c9e0db68b0dd..58196f73e66e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java @@ -37,6 +37,7 @@ public class UnlockMethodCache { private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; private final ArrayList<OnUnlockMethodChangedListener> mListeners = new ArrayList<>(); private boolean mMethodInsecure; + private boolean mTrustManaged; private UnlockMethodCache(Context ctx) { mLockPatternUtils = new LockPatternUtils(ctx); @@ -71,9 +72,11 @@ public class UnlockMethodCache { int user = mLockPatternUtils.getCurrentUser(); boolean methodInsecure = !mLockPatternUtils.isSecure() || mKeyguardUpdateMonitor.getUserHasTrust(user); - boolean changed = methodInsecure != mMethodInsecure; + boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user); + boolean changed = methodInsecure != mMethodInsecure || trustManaged != mTrustManaged; if (changed || updateAlways) { mMethodInsecure = methodInsecure; + mTrustManaged = trustManaged; notifyListeners(mMethodInsecure); } } @@ -96,15 +99,25 @@ public class UnlockMethodCache { } @Override + public void onTrustManagedChanged(int userId) { + updateMethodSecure(false /* updateAlways */); + } + + @Override public void onScreenTurnedOn() { updateMethodSecure(false /* updateAlways */); } + @Override public void onFingerprintRecognized(int userId) { updateMethodSecure(false /* updateAlways */); } }; + public boolean isTrustManaged() { + return mTrustManaged; + } + public static interface OnUnlockMethodChangedListener { void onMethodSecureChanged(boolean methodSecure); } diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java index 0acb82ffff57..ee20b3c3c7a7 100644 --- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java +++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java @@ -17,12 +17,11 @@ 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.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -51,7 +50,8 @@ 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; + private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5; + private static final int MSG_MANAGING_TRUST = 6; /** * Time in uptime millis that we wait for the service connection, both when starting @@ -77,6 +77,8 @@ public class TrustAgentWrapper { private boolean mTrusted; private CharSequence mMessage; private boolean mTrustDisabledByDpm; + private boolean mManagingTrust; + private IBinder mSetTrustAgentFeaturesToken; private final Handler mHandler = new Handler() { @Override @@ -119,8 +121,30 @@ public class TrustAgentWrapper { unbind(); mTrustManagerService.resetAgent(mName, mUserId); break; - case MSG_DPM_CHANGED: - updateDevicePolicyFeatures(mName); + case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED: + IBinder token = (IBinder) msg.obj; + boolean result = msg.arg1 != 0; + if (mSetTrustAgentFeaturesToken == token) { + mSetTrustAgentFeaturesToken = null; + if (mTrustDisabledByDpm && result) { + if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged " + + "enabled features: " + mName); + mTrustDisabledByDpm = false; + mTrustManagerService.updateTrust(mUserId); + } + } else { + if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED " + + "with obsolete token: " + mName); + } + break; + case MSG_MANAGING_TRUST: + mManagingTrust = msg.arg1 != 0; + if (!mManagingTrust) { + mTrusted = false; + mMessage = null; + } + mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust); + mTrustManagerService.updateTrust(mUserId); break; } } @@ -144,6 +168,19 @@ public class TrustAgentWrapper { if (DEBUG) Slog.v(TAG, "revokeTrust()"); mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); } + + @Override + public void setManagingTrust(boolean managingTrust) { + if (DEBUG) Slog.v(TAG, "managingTrust()"); + mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); + } + + @Override + public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) { + if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); + mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, + result ? 1 : 0, 0, token).sendToTarget(); + } }; private final ServiceConnection mConnection = new ServiceConnection() { @@ -154,32 +191,21 @@ public class TrustAgentWrapper { mTrustAgentService = ITrustAgentService.Stub.asInterface(service); mTrustManagerService.mArchive.logAgentConnected(mUserId, name); setCallback(mCallback); - updateDevicePolicyFeatures(name); - watchForDpmChanges(true); + updateDevicePolicyFeatures(); } @Override public void onServiceDisconnected(ComponentName name) { if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString()); mTrustAgentService = null; + mManagingTrust = false; + mSetTrustAgentFeaturesToken = null; mTrustManagerService.mArchive.logAgentDied(mUserId, name); mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 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); - } } }; @@ -223,48 +249,32 @@ 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 updateDevicePolicyFeatures() { boolean trustDisabled = false; - if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + name + ")"); + if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")"); 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 + + if ((dpm.getKeyguardDisabledFeatures(null) + & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) { + List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName); + trustDisabled = true; + 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 " + mName.flattenToShortString() + + " disabled until it acknowledges "+ features); } + mSetTrustAgentFeaturesToken = new Binder(); + mTrustAgentService.setTrustAgentFeaturesEnabled(bundle, + mSetTrustAgentFeaturesToken); } - } else { - Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?", - new IllegalStateException("Stack trace:")); } } } catch (RemoteException e) { @@ -278,7 +288,11 @@ public class TrustAgentWrapper { } public boolean isTrusted() { - return mTrusted && !mTrustDisabledByDpm; + return mTrusted && mManagingTrust && !mTrustDisabledByDpm; + } + + public boolean isManagingTrust() { + return mManagingTrust && !mTrustDisabledByDpm; } public CharSequence getMessage() { @@ -294,6 +308,7 @@ public class TrustAgentWrapper { mContext.unbindService(mConnection); mBound = false; mTrustAgentService = null; + mSetTrustAgentFeaturesToken = null; mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); mHandler.removeMessages(MSG_RESTART_TIMEOUT); } diff --git a/services/core/java/com/android/server/trust/TrustArchive.java b/services/core/java/com/android/server/trust/TrustArchive.java index 5e32d86d27c0..d4ed86d4183d 100644 --- a/services/core/java/com/android/server/trust/TrustArchive.java +++ b/services/core/java/com/android/server/trust/TrustArchive.java @@ -35,6 +35,7 @@ public class TrustArchive { private static final int TYPE_AGENT_DIED = 3; private static final int TYPE_AGENT_CONNECTED = 4; private static final int TYPE_AGENT_STOPPED = 5; + private static final int TYPE_MANAGING_TRUST = 6; private static final int HISTORY_LIMIT = 200; @@ -49,8 +50,11 @@ public class TrustArchive { final long duration; final boolean userInitiated; + // managingTrust + final boolean managingTrust; + private Event(int type, int userId, ComponentName agent, String message, - long duration, boolean userInitiated) { + long duration, boolean userInitiated, boolean managingTrust) { this.type = type; this.userId = userId; this.agent = agent; @@ -58,6 +62,7 @@ public class TrustArchive { this.message = message; this.duration = duration; this.userInitiated = userInitiated; + this.managingTrust = managingTrust; } } @@ -66,27 +71,31 @@ public class TrustArchive { public void logGrantTrust(int userId, ComponentName agent, String message, long duration, boolean userInitiated) { addEvent(new Event(TYPE_GRANT_TRUST, userId, agent, message, duration, - userInitiated)); + userInitiated, false)); } public void logRevokeTrust(int userId, ComponentName agent) { - addEvent(new Event(TYPE_REVOKE_TRUST, userId, agent, null, 0, false)); + addEvent(new Event(TYPE_REVOKE_TRUST, userId, agent, null, 0, false, false)); } public void logTrustTimeout(int userId, ComponentName agent) { - addEvent(new Event(TYPE_TRUST_TIMEOUT, userId, agent, null, 0, false)); + addEvent(new Event(TYPE_TRUST_TIMEOUT, userId, agent, null, 0, false, false)); } public void logAgentDied(int userId, ComponentName agent) { - addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false)); + addEvent(new Event(TYPE_AGENT_DIED, userId, agent, null, 0, false, false)); } public void logAgentConnected(int userId, ComponentName agent) { - addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, false)); + addEvent(new Event(TYPE_AGENT_CONNECTED, userId, agent, null, 0, false, false)); } public void logAgentStopped(int userId, ComponentName agent) { - addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, false)); + addEvent(new Event(TYPE_AGENT_STOPPED, userId, agent, null, 0, false, false)); + } + + public void logManagingTrust(int userId, ComponentName agent, boolean managing) { + addEvent(new Event(TYPE_MANAGING_TRUST, userId, agent, null, 0, false, managing)); } private void addEvent(Event e) { @@ -123,6 +132,9 @@ public class TrustArchive { writer.printf(", message=\"%s\", duration=%s", ev.message, formatDuration(ev.duration)); break; + case TYPE_MANAGING_TRUST: + writer.printf(", managingTrust=" + ev.managingTrust); + break; default: } writer.println(); @@ -166,6 +178,8 @@ public class TrustArchive { return "AgentConnected"; case TYPE_AGENT_STOPPED: return "AgentStopped"; + case TYPE_MANAGING_TRUST: + return "ManagingTrust"; default: return "Unknown(" + type + ")"; } diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 9c2df55d8425..d3b8d5d1e8d2 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -153,10 +153,11 @@ public class TrustManagerService extends SystemService { } public void updateTrust(int userId) { + dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId); dispatchOnTrustChanged(aggregateIsTrusted(userId), userId); } - protected void refreshAgentList() { + void refreshAgentList() { if (DEBUG) Slog.d(TAG, "refreshAgentList()"); PackageManager pm = mContext.getPackageManager(); @@ -167,13 +168,13 @@ public class TrustManagerService extends SystemService { obsoleteAgents.addAll(mActiveAgents); for (UserInfo userInfo : userInfos) { - int disabledFeatures = lockPatternUtils.getDevicePolicyManager() - .getKeyguardDisabledFeatures(null, userInfo.id); + DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager(); + int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id); final boolean disableTrustAgents = (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0; List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id); - if (disableTrustAgents || enabledAgents == null) { + if (enabledAgents == null) { continue; } List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT, @@ -192,6 +193,13 @@ public class TrustManagerService extends SystemService { ComponentName name = getComponentName(resolveInfo); if (!enabledAgents.contains(name)) continue; + if (disableTrustAgents) { + List<String> features = + dpm.getTrustAgentFeaturesEnabled(null /* admin */, name); + // Disable agent if no features are enabled. + if (features == null || features.isEmpty()) continue; + } + AgentInfo agentInfo = new AgentInfo(); agentInfo.component = name; agentInfo.userId = userInfo.id; @@ -211,7 +219,7 @@ public class TrustManagerService extends SystemService { boolean trustMayHaveChanged = false; for (int i = 0; i < obsoleteAgents.size(); i++) { AgentInfo info = obsoleteAgents.valueAt(i); - if (info.agent.isTrusted()) { + if (info.agent.isManagingTrust()) { trustMayHaveChanged = true; } info.agent.unbind(); @@ -223,13 +231,22 @@ public class TrustManagerService extends SystemService { } } + void updateDevicePolicyFeatures(int userId) { + for (int i = 0; i < mActiveAgents.size(); i++) { + AgentInfo info = mActiveAgents.valueAt(i); + if (info.agent.isConnected()) { + info.agent.updateDevicePolicyFeatures(); + } + } + } + private void removeAgentsOfPackage(String packageName) { boolean trustMayHaveChanged = false; for (int i = mActiveAgents.size() - 1; i >= 0; i--) { AgentInfo info = mActiveAgents.valueAt(i); if (packageName.equals(info.component.getPackageName())) { Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); - if (info.agent.isTrusted()) { + if (info.agent.isManagingTrust()) { trustMayHaveChanged = true; } info.agent.unbind(); @@ -247,7 +264,7 @@ public class TrustManagerService extends SystemService { AgentInfo info = mActiveAgents.valueAt(i); if (name.equals(info.component) && userId == info.userId) { Log.i(TAG, "Resetting agent " + info.component.flattenToShortString()); - if (info.agent.isTrusted()) { + if (info.agent.isManagingTrust()) { trustMayHaveChanged = true; } info.agent.unbind(); @@ -333,6 +350,21 @@ public class TrustManagerService extends SystemService { return false; } + private boolean aggregateIsTrustManaged(int userId) { + if (!mUserHasAuthenticatedSinceBoot.get(userId)) { + return false; + } + for (int i = 0; i < mActiveAgents.size(); i++) { + AgentInfo info = mActiveAgents.valueAt(i); + if (info.userId == userId) { + if (info.agent.isManagingTrust()) { + return true; + } + } + } + return false; + } + private void dispatchUnlockAttempt(boolean successful, int userId) { for (int i = 0; i < mActiveAgents.size(); i++) { AgentInfo info = mActiveAgents.valueAt(i); @@ -383,7 +415,21 @@ public class TrustManagerService extends SystemService { try { mTrustListeners.get(i).onTrustChanged(enabled, userId); } catch (DeadObjectException e) { - if (DEBUG) Slog.d(TAG, "Removing dead TrustListener."); + Slog.d(TAG, "Removing dead TrustListener."); + mTrustListeners.remove(i); + i--; + } catch (RemoteException e) { + Slog.e(TAG, "Exception while notifying TrustListener.", e); + } + } + } + + private void dispatchOnTrustManagedChanged(boolean managed, int userId) { + for (int i = 0; i < mTrustListeners.size(); i++) { + try { + mTrustListeners.get(i).onTrustManagedChanged(managed, userId); + } catch (DeadObjectException e) { + Slog.d(TAG, "Removing dead TrustListener."); mTrustListeners.remove(i); i--; } catch (RemoteException e) { @@ -472,6 +518,7 @@ public class TrustManagerService extends SystemService { fout.print(" (current)"); } fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id))); + fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id))); fout.println(); fout.println(" Enabled agents:"); boolean duplicateSimpleNames = false; @@ -482,7 +529,9 @@ public class TrustManagerService extends SystemService { fout.print(" "); fout.println(info.component.flattenToShortString()); fout.print(" bound=" + dumpBool(info.agent.isBound())); fout.print(", connected=" + dumpBool(info.agent.isConnected())); - fout.println(", trusted=" + dumpBool(trusted)); + fout.print(", managingTrust=" + dumpBool(info.agent.isManagingTrust())); + fout.print(", trusted=" + dumpBool(trusted)); + fout.println(); if (trusted) { fout.println(" message=\"" + info.agent.getMessage() + "\""); } @@ -554,6 +603,7 @@ public class TrustManagerService extends SystemService { if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals( intent.getAction())) { refreshAgentList(); + updateDevicePolicyFeatures(getSendingUserId()); } } |