From b5e4722891e7bbf2fffcd995af02838667a3abab Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 14 Aug 2015 15:53:06 -0700 Subject: Add StrongAuthTracker Bug: 22846469 Bug: 22115393 Change-Id: I6ef5322d02e540fc043e7f20d3aabf595ce7c224 --- Android.mk | 1 + .../java/android/app/trust/IStrongAuthTracker.aidl | 26 +++ core/java/android/app/trust/ITrustManager.aidl | 2 - core/java/android/app/trust/TrustManager.java | 38 +---- .../com/android/internal/widget/ILockSettings.aidl | 4 + .../android/internal/widget/LockPatternUtils.java | 184 ++++++++++++++++++++- .../android/keyguard/KeyguardUpdateMonitor.java | 32 +++- .../systemui/keyguard/KeyguardViewMediator.java | 2 +- .../com/android/server/LockSettingsService.java | 25 ++- .../com/android/server/LockSettingsStrongAuth.java | 167 +++++++++++++++++++ .../android/server/trust/TrustManagerService.java | 112 +++---------- .../devicepolicy/DevicePolicyManagerService.java | 8 +- 12 files changed, 462 insertions(+), 139 deletions(-) create mode 100644 core/java/android/app/trust/IStrongAuthTracker.aidl create mode 100644 services/core/java/com/android/server/LockSettingsStrongAuth.java diff --git a/Android.mk b/Android.mk index 18d9c69..2a87fd2 100644 --- a/Android.mk +++ b/Android.mk @@ -90,6 +90,7 @@ LOCAL_SRC_FILES += \ core/java/android/app/IWallpaperManager.aidl \ core/java/android/app/IWallpaperManagerCallback.aidl \ core/java/android/app/admin/IDevicePolicyManager.aidl \ + core/java/android/app/trust/IStrongAuthTracker.aidl \ core/java/android/app/trust/ITrustManager.aidl \ core/java/android/app/trust/ITrustListener.aidl \ core/java/android/app/backup/IBackupManager.aidl \ diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl new file mode 100644 index 0000000..36c71bf --- /dev/null +++ b/core/java/android/app/trust/IStrongAuthTracker.aidl @@ -0,0 +1,26 @@ +/* +** +** Copyright 2015, 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. +*/ +package android.app.trust; + +/** + * Private API to be notified about strong auth changes + * + * {@hide} + */ +oneway interface IStrongAuthTracker { + void onStrongAuthRequiredChanged(int strongAuthRequired, int userId); +} \ No newline at end of file diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl index 32951d9..2dea545 100644 --- a/core/java/android/app/trust/ITrustManager.aidl +++ b/core/java/android/app/trust/ITrustManager.aidl @@ -26,11 +26,9 @@ import android.app.trust.ITrustListener; interface ITrustManager { void reportUnlockAttempt(boolean successful, int userId); void reportEnabledTrustAgentsChanged(int userId); - void reportRequireCredentialEntry(int userId); void registerTrustListener(in ITrustListener trustListener); void unregisterTrustListener(in ITrustListener trustListener); void reportKeyguardShowingChanged(); boolean isDeviceLocked(int userId); boolean isDeviceSecure(int userId); - boolean hasUserAuthenticatedSinceBoot(int userId); } diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java index 8cab565..aff69f0 100644 --- a/core/java/android/app/trust/TrustManager.java +++ b/core/java/android/app/trust/TrustManager.java @@ -16,13 +16,19 @@ package android.app.trust; +import android.annotation.IntDef; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Log; +import android.util.SparseIntArray; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * See {@link com.android.server.trust.TrustManagerService} @@ -73,21 +79,6 @@ public class TrustManager { } /** - * Reports that trust is disabled until credentials have been entered for user {@param userId}. - * - * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. - * - * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} - */ - public void reportRequireCredentialEntry(int userId) { - try { - mService.reportRequireCredentialEntry(userId); - } catch (RemoteException e) { - onError(e); - } - } - - /** * Reports that the visibility of the keyguard has changed. * * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. @@ -147,23 +138,6 @@ public class TrustManager { } } - /** - * Checks whether the specified user has been authenticated since the last boot. - * - * @param userId the user id of the user to check for - * @return true if the user has authenticated since boot, false otherwise - * - * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. - */ - public boolean hasUserAuthenticatedSinceBoot(int userId) { - try { - return mService.hasUserAuthenticatedSinceBoot(userId); - } catch (RemoteException e) { - onError(e); - return false; - } - } - private void onError(Exception e) { Log.e(TAG, "Error while calling TrustManagerService", e); } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index dfb7c50..4e4552d 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -16,6 +16,7 @@ package com.android.internal.widget; +import android.app.trust.IStrongAuthTracker; import com.android.internal.widget.VerifyCredentialResponse; /** {@hide} */ @@ -35,4 +36,7 @@ interface ILockSettings { boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); + void registerStrongAuthTracker(in IStrongAuthTracker tracker); + void unregisterStrongAuthTracker(in IStrongAuthTracker tracker); + void requireStrongAuth(int strongAuthReason, int userId); } diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 86d11be..b3871f1 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -16,18 +16,19 @@ package com.android.internal.widget; -import android.Manifest; +import android.annotation.IntDef; import android.app.ActivityManager; -import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; +import android.app.trust.IStrongAuthTracker; import android.app.trust.TrustManager; -import android.bluetooth.BluetoothClass; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.pm.PackageManager; import android.os.AsyncTask; +import android.os.Handler; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -38,9 +39,12 @@ import android.os.storage.StorageManager; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.util.SparseIntArray; import com.google.android.collect.Lists; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -228,7 +232,7 @@ public class LockPatternUtils { public void reportFailedPasswordAttempt(int userId) { getDevicePolicyManager().reportFailedPasswordAttempt(userId); getTrustManager().reportUnlockAttempt(false /* authenticated */, userId); - getTrustManager().reportRequireCredentialEntry(userId); + requireCredentialEntry(userId); } public void reportSuccessfulPasswordAttempt(int userId) { @@ -1163,10 +1167,32 @@ public class LockPatternUtils { } /** - * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int) + * Disable trust until credentials have been entered for user {@param userId}. + * + * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. + * + * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} */ public void requireCredentialEntry(int userId) { - getTrustManager().reportRequireCredentialEntry(userId); + requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId); + } + + /** + * Requests strong authentication for user {@param userId}. + * + * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission. + * + * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating + * the reason for and the strength of the requested authentication. + * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL} + */ + public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason, + int userId) { + try { + getLockSettings().requireStrongAuth(strongAuthReason, userId); + } catch (RemoteException e) { + Log.e(TAG, "Error while requesting strong auth: " + e); + } } private void onAfterChangingPassword(int userHandle) { @@ -1198,4 +1224,148 @@ public class LockPatternUtils { private boolean shouldEncryptWithCredentials(boolean defaultValue) { return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet(); } + + + public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) { + try { + getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub); + } catch (RemoteException e) { + throw new RuntimeException("Could not register StrongAuthTracker"); + } + } + + public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) { + try { + getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub); + } catch (RemoteException e) { + Log.e(TAG, "Could not unregister StrongAuthTracker", e); + } + } + + /** + * Tracks the global strong authentication state. + */ + public static class StrongAuthTracker { + + @IntDef(flag = true, + value = { STRONG_AUTH_NOT_REQUIRED, + STRONG_AUTH_REQUIRED_AFTER_BOOT, + STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, + SOME_AUTH_REQUIRED_AFTER_USER_REQUEST}) + @Retention(RetentionPolicy.SOURCE) + public @interface StrongAuthFlags {} + + /** + * Strong authentication is not required. + */ + public static final int STRONG_AUTH_NOT_REQUIRED = 0x0; + + /** + * Strong authentication is required because the user has not authenticated since boot. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1; + + /** + * Strong authentication is required because a device admin has requested it. + */ + public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2; + + /** + * Some authentication is required because the user has temporarily disabled trust. + */ + public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4; + + public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT; + private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST; + + final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray(); + + private final H mHandler; + + public StrongAuthTracker() { + this(Looper.myLooper()); + } + + /** + * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged} + * will be scheduled. + */ + public StrongAuthTracker(Looper looper) { + mHandler = new H(looper); + } + + /** + * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required, + * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong + * authentication is required. + * + * @param userId the user for whom the state is queried. + */ + public @StrongAuthFlags int getStrongAuthForUser(int userId) { + return mStrongAuthRequiredForUser.get(userId, DEFAULT); + } + + /** + * @return true if unlocking with trust alone is allowed for {@param userId} by the current + * strong authentication requirements. + */ + public boolean isTrustAllowedForUser(int userId) { + return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED; + } + + /** + * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the + * current strong authentication requirements. + */ + public boolean isFingerprintAllowedForUser(int userId) { + return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0; + } + + /** + * Called when the strong authentication requirements for {@param userId} changed. + */ + public void onStrongAuthRequiredChanged(int userId) { + } + + void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags, + int userId) { + + int oldValue = getStrongAuthForUser(userId); + if (strongAuthFlags != oldValue) { + if (strongAuthFlags == DEFAULT) { + mStrongAuthRequiredForUser.delete(userId); + } else { + mStrongAuthRequiredForUser.put(userId, strongAuthFlags); + } + onStrongAuthRequiredChanged(userId); + } + } + + + final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() { + @Override + public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags, + int userId) { + mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED, + strongAuthFlags, userId).sendToTarget(); + } + }; + + private class H extends Handler { + static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1; + + public H(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED: + handleStrongAuthRequiredChanged(msg.arg1, msg.arg2); + break; + } + } + }; + } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index afa5ae2..cb39e77 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -58,6 +58,7 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.IccCardConstants.State; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.widget.LockPatternUtils; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -170,7 +171,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean mFingerprintAlreadyAuthenticated; private boolean mBouncer; private boolean mBootCompleted; - private boolean mUserHasAuthenticatedSinceBoot; // Device provisioning state private boolean mDeviceProvisioned; @@ -183,6 +183,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { /** Tracks whether strong authentication hasn't been used since quite some time per user. */ private ArraySet mStrongAuthTimedOut = new ArraySet<>(); + private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker(); private final ArrayList> mCallbacks = Lists.newArrayList(); @@ -539,7 +540,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } public boolean isUnlockingWithFingerprintAllowed() { - return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser); + return mStrongAuthTracker.isUnlockingWithFingerprintAllowed() + && !hasFingerprintUnlockTimedOut(sCurrentUser); + } + + public StrongAuthTracker getStrongAuthTracker() { + return mStrongAuthTracker; } /** @@ -827,6 +833,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } + public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker { + + public boolean isUnlockingWithFingerprintAllowed() { + int userId = getCurrentUser(); + return isFingerprintAllowedForUser(userId); + } + + public boolean hasUserAuthenticatedSinceBoot() { + int userId = getCurrentUser(); + return (getStrongAuthForUser(userId) + & STRONG_AUTH_REQUIRED_AFTER_BOOT) == 0; + } + + @Override + public void onStrongAuthRequiredChanged(int userId) { + // do something? + } + } + public static KeyguardUpdateMonitor getInstance(Context context) { if (sInstance == null) { sInstance = new KeyguardUpdateMonitor(context); @@ -973,6 +998,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { PERMISSION_SELF, null /* handler */); mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); mTrustManager.registerTrustListener(this); + new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker); mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); updateFingerprintListeningState(); @@ -1001,8 +1027,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { if (DEBUG) Log.v(TAG, "startListeningForFingerprint()"); int userId = ActivityManager.getCurrentUser(); if (isUnlockWithFingerprintPossible(userId)) { - mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot( - ActivityManager.getCurrentUser()); if (mFingerprintCancelSignal != null) { mFingerprintCancelSignal.cancel(); } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index ce91d5b..647b272 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -531,7 +531,7 @@ public class KeyguardViewMediator extends SystemUI { int currentUser = ActivityManager.getCurrentUser(); if ((mUpdateMonitor.getUserTrustIsManaged(currentUser) || mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser)) - && !mTrustManager.hasUserAuthenticatedSinceBoot(currentUser)) { + && !mUpdateMonitor.getStrongAuthTracker().hasUserAuthenticatedSinceBoot()) { return KeyguardSecurityView.PROMPT_REASON_RESTART; } else if (mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser) && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) { diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index 5e2fe5a..005d6a4 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -18,6 +18,7 @@ package com.android.server; import android.app.admin.DevicePolicyManager; import android.app.backup.BackupManager; +import android.app.trust.IStrongAuthTracker; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -70,6 +71,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final Context mContext; private final LockSettingsStorage mStorage; + private final LockSettingsStrongAuth mStrongAuth = new LockSettingsStrongAuth(); private LockPatternUtils mLockPatternUtils; private boolean mFirstCallToVold; @@ -93,6 +95,7 @@ public class LockSettingsService extends ILockSettings.Stub { filter.addAction(Intent.ACTION_USER_ADDED); filter.addAction(Intent.ACTION_USER_STARTING); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_PRESENT); mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() { @@ -122,6 +125,8 @@ public class LockSettingsService extends ILockSettings.Stub { } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) { final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); mStorage.prefetchUser(userHandle); + } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) { + mStrongAuth.reportUnlock(getSendingUserId()); } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); if (userHandle > 0) { @@ -713,6 +718,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void removeUser(int userId) { mStorage.removeUser(userId); + mStrongAuth.removeUser(userId); final KeyStore ks = KeyStore.getInstance(); ks.onUserRemoved(userId); @@ -727,6 +733,24 @@ public class LockSettingsService extends ILockSettings.Stub { } } + @Override + public void registerStrongAuthTracker(IStrongAuthTracker tracker) { + checkPasswordReadPermission(UserHandle.USER_ALL); + mStrongAuth.registerStrongAuthTracker(tracker); + } + + @Override + public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) { + checkPasswordReadPermission(UserHandle.USER_ALL); + mStrongAuth.unregisterStrongAuthTracker(tracker); + } + + @Override + public void requireStrongAuth(int strongAuthReason, int userId) { + checkWritePermission(userId); + mStrongAuth.requireStrongAuth(strongAuthReason, userId); + } + private static final String[] VALID_SETTINGS = new String[] { LockPatternUtils.LOCKOUT_PERMANENT_KEY, LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE, @@ -797,5 +821,4 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.e(TAG, "Unable to acquire GateKeeperService"); return null; } - } diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java new file mode 100644 index 0000000..c023f4a --- /dev/null +++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2015 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 + */ + +package com.android.server; + +import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker; + +import android.app.trust.IStrongAuthTracker; +import android.os.DeadObjectException; +import android.os.Handler; +import android.os.Message; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Slog; +import android.util.SparseIntArray; + +import java.util.ArrayList; + +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED; + +/** + * Keeps track of requests for strong authentication. + */ +public class LockSettingsStrongAuth { + + private static final String TAG = "LockSettings"; + + private static final int MSG_REQUIRE_STRONG_AUTH = 1; + private static final int MSG_REGISTER_TRACKER = 2; + private static final int MSG_UNREGISTER_TRACKER = 3; + private static final int MSG_REMOVE_USER = 4; + + private final ArrayList mStrongAuthTrackers = new ArrayList<>(); + private final SparseIntArray mStrongAuthForUser = new SparseIntArray(); + + private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) { + for (int i = 0; i < mStrongAuthTrackers.size(); i++) { + if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) { + return; + } + } + mStrongAuthTrackers.add(tracker); + + for (int i = 0; i < mStrongAuthForUser.size(); i++) { + int key = mStrongAuthForUser.keyAt(i); + int value = mStrongAuthForUser.valueAt(i); + try { + tracker.onStrongAuthRequiredChanged(value, key); + } catch (RemoteException e) { + Slog.e(TAG, "Exception while adding StrongAuthTracker.", e); + } + } + } + + private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) { + for (int i = 0; i < mStrongAuthTrackers.size(); i++) { + if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) { + mStrongAuthTrackers.remove(i); + return; + } + } + } + + private void handleRequireStrongAuth(int strongAuthReason, int userId) { + if (userId == UserHandle.USER_ALL) { + for (int i = 0; i < mStrongAuthForUser.size(); i++) { + int key = mStrongAuthForUser.keyAt(i); + handleRequireStrongAuthOneUser(strongAuthReason, key); + } + } else { + handleRequireStrongAuthOneUser(strongAuthReason, userId); + } + } + + private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) { + int oldValue = mStrongAuthForUser.get(userId, LockPatternUtils.StrongAuthTracker.DEFAULT); + int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED + ? STRONG_AUTH_NOT_REQUIRED + : (oldValue | strongAuthReason); + if (oldValue != newValue) { + mStrongAuthForUser.put(userId, newValue); + notifyStrongAuthTrackers(newValue, userId); + } + } + + private void handleRemoveUser(int userId) { + int index = mStrongAuthForUser.indexOfKey(userId); + if (index >= 0) { + mStrongAuthForUser.removeAt(index); + notifyStrongAuthTrackers(StrongAuthTracker.DEFAULT, userId); + } + } + + private void notifyStrongAuthTrackers(int strongAuthReason, int userId) { + for (int i = 0; i < mStrongAuthTrackers.size(); i++) { + try { + mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId); + } catch (DeadObjectException e) { + Slog.d(TAG, "Removing dead StrongAuthTracker."); + mStrongAuthTrackers.remove(i); + i--; + } catch (RemoteException e) { + Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e); + } + } + } + + public void registerStrongAuthTracker(IStrongAuthTracker tracker) { + mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget(); + } + + public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) { + mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget(); + } + + public void removeUser(int userId) { + mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget(); + } + + public void requireStrongAuth(int strongAuthReason, int userId) { + if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) { + mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason, + userId).sendToTarget(); + } else { + throw new IllegalArgumentException( + "userId must be an explicit user id or USER_ALL"); + } + } + + public void reportUnlock(int userId) { + requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId); + } + + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_REGISTER_TRACKER: + handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj); + break; + case MSG_UNREGISTER_TRACKER: + handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj); + break; + case MSG_REQUIRE_STRONG_AUTH: + handleRequireStrongAuth(msg.arg1, msg.arg2); + break; + case MSG_REMOVE_USER: + handleRemoveUser(msg.arg1); + break; + } + } + }; +} diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 15da829..6c70fe9 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -19,6 +19,7 @@ package com.android.server.trust; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockPatternUtils.StrongAuthTracker; import com.android.server.SystemService; import org.xmlpull.v1.XmlPullParser; @@ -59,6 +60,7 @@ import android.util.AttributeSet; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManagerGlobal; @@ -96,16 +98,15 @@ public class TrustManagerService extends SystemService { private static final int MSG_UNREGISTER_LISTENER = 2; private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3; private static final int MSG_ENABLED_AGENTS_CHANGED = 4; - private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5; private static final int MSG_KEYGUARD_SHOWING_CHANGED = 6; private static final int MSG_START_USER = 7; private static final int MSG_CLEANUP_USER = 8; private static final int MSG_SWITCH_USER = 9; - private final ArraySet mActiveAgents = new ArraySet(); - private final ArrayList mTrustListeners = new ArrayList(); + private final ArraySet mActiveAgents = new ArraySet<>(); + private final ArrayList mTrustListeners = new ArrayList<>(); private final Receiver mReceiver = new Receiver(); - private final SparseBooleanArray mUserHasAuthenticated = new SparseBooleanArray(); + /* package */ final TrustArchive mArchive = new TrustArchive(); private final Context mContext; private final LockPatternUtils mLockPatternUtils; @@ -118,9 +119,6 @@ public class TrustManagerService extends SystemService { @GuardedBy("mDeviceLockedForUser") private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray(); - @GuardedBy("mUserHasAuthenticatedSinceBoot") - private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray(); - private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_OWNER; @@ -146,6 +144,7 @@ public class TrustManagerService extends SystemService { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); mReceiver.register(mContext); + mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker); } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { mTrustAgentsCanRun = true; refreshAgentList(UserHandle.USER_ALL); @@ -230,7 +229,7 @@ public class TrustManagerService extends SystemService { if (!userInfo.supportsSwitchTo()) continue; if (!mActivityManager.isUserRunning(userInfo.id)) continue; if (!lockPatternUtils.isSecure(userInfo.id)) continue; - if (!getUserHasAuthenticated(userInfo.id)) continue; + if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue; DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager(); int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id); final boolean disableTrustAgents = @@ -509,7 +508,7 @@ public class TrustManagerService extends SystemService { // Agent dispatch and aggregation private boolean aggregateIsTrusted(int userId) { - if (!getUserHasAuthenticated(userId)) { + if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) { return false; } for (int i = 0; i < mActiveAgents.size(); i++) { @@ -524,7 +523,7 @@ public class TrustManagerService extends SystemService { } private boolean aggregateIsTrustManaged(int userId) { - if (!getUserHasAuthenticated(userId)) { + if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) { return false; } for (int i = 0; i < mActiveAgents.size(); i++) { @@ -545,54 +544,6 @@ public class TrustManagerService extends SystemService { info.agent.onUnlockAttempt(successful); } } - - if (successful) { - updateUserHasAuthenticated(userId); - } - } - - private void updateUserHasAuthenticated(int userId) { - boolean changed = setUserHasAuthenticated(userId); - if (changed) { - refreshAgentList(userId); - } - } - - private boolean getUserHasAuthenticated(int userId) { - return mUserHasAuthenticated.get(userId); - } - - /** - * @return whether the value has changed - */ - private boolean setUserHasAuthenticated(int userId) { - if (!mUserHasAuthenticated.get(userId)) { - mUserHasAuthenticated.put(userId, true); - synchronized (mUserHasAuthenticatedSinceBoot) { - mUserHasAuthenticatedSinceBoot.put(userId, true); - } - return true; - } - return false; - } - - private void clearUserHasAuthenticated(int userId) { - if (userId == UserHandle.USER_ALL) { - mUserHasAuthenticated.clear(); - } else { - mUserHasAuthenticated.put(userId, false); - } - } - - private boolean getUserHasAuthenticatedSinceBoot(int userId) { - synchronized (mUserHasAuthenticatedSinceBoot) { - return mUserHasAuthenticatedSinceBoot.get(userId); - } - } - - private void requireCredentialEntry(int userId) { - clearUserHasAuthenticated(userId); - refreshAgentList(userId); } // Listeners @@ -681,17 +632,6 @@ public class TrustManagerService extends SystemService { } @Override - public void reportRequireCredentialEntry(int userId) throws RemoteException { - enforceReportPermission(); - if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) { - mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget(); - } else { - throw new IllegalArgumentException( - "userId must be an explicit user id or USER_ALL"); - } - } - - @Override public void reportKeyguardShowingChanged() throws RemoteException { enforceReportPermission(); // coalesce refresh messages. @@ -734,18 +674,6 @@ public class TrustManagerService extends SystemService { } } - @Override - public boolean hasUserAuthenticatedSinceBoot(int userId) throws RemoteException { - mContext.enforceCallingOrSelfPermission( - Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, null); - long token = Binder.clearCallingIdentity(); - try { - return getUserHasAuthenticatedSinceBoot(userId); - } finally { - Binder.restoreCallingIdentity(token); - } - } - private void enforceReportPermission() { mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); @@ -794,9 +722,8 @@ public class TrustManagerService extends SystemService { fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id))); fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id))); fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id))); - fout.print(", hasAuthenticated=" + dumpBool(getUserHasAuthenticated(user.id))); - fout.print(", hasAuthenticatedSinceBoot=" - + dumpBool(getUserHasAuthenticatedSinceBoot(user.id))); + fout.print(", strongAuthRequired=" + dumpHex( + mStrongAuthTracker.getStrongAuthForUser(user.id))); fout.println(); fout.println(" Enabled agents:"); boolean duplicateSimpleNames = false; @@ -831,6 +758,10 @@ public class TrustManagerService extends SystemService { private String dumpBool(boolean b) { return b ? "1" : "0"; } + + private String dumpHex(int i) { + return "0x" + Integer.toHexString(i); + } }; private int resolveProfileParent(int userId) { @@ -864,9 +795,6 @@ public class TrustManagerService extends SystemService { // This is also called when the security mode of a user changes. refreshDeviceLockedForUser(UserHandle.USER_ALL); break; - case MSG_REQUIRE_CREDENTIAL_ENTRY: - requireCredentialEntry(msg.arg1); - break; case MSG_KEYGUARD_SHOWING_CHANGED: refreshDeviceLockedForUser(mCurrentUser); break; @@ -900,6 +828,13 @@ public class TrustManagerService extends SystemService { } }; + private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker() { + @Override + public void onStrongAuthRequiredChanged(int userId) { + refreshAgentList(userId); + } + }; + private class Receiver extends BroadcastReceiver { @Override @@ -908,8 +843,6 @@ public class TrustManagerService extends SystemService { if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { refreshAgentList(getSendingUserId()); updateDevicePolicyFeatures(); - } else if (Intent.ACTION_USER_PRESENT.equals(action)) { - updateUserHasAuthenticated(getSendingUserId()); } else if (Intent.ACTION_USER_ADDED.equals(action)) { int userId = getUserId(intent); if (userId > 0) { @@ -918,7 +851,6 @@ public class TrustManagerService extends SystemService { } else if (Intent.ACTION_USER_REMOVED.equals(action)) { int userId = getUserId(intent); if (userId > 0) { - mUserHasAuthenticated.delete(userId); synchronized (mUserIsTrusted) { mUserIsTrusted.delete(userId); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cd2885b..dedf1d9 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA; import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES; +import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; import static org.xmlpull.v1.XmlPullParser.END_TAG; import static org.xmlpull.v1.XmlPullParser.TEXT; @@ -44,6 +45,7 @@ import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; import android.app.admin.SystemUpdatePolicy; import android.app.backup.IBackupManager; +import android.app.trust.TrustManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -2957,7 +2959,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { - utils.requireCredentialEntry(UserHandle.USER_ALL); + utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, + UserHandle.USER_ALL); } synchronized (this) { int newOwner = requireEntry ? callingUid : -1; @@ -3089,7 +3092,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0); // Ensure the device is locked - new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL); + new LockPatternUtils(mContext).requireStrongAuth( + STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL); getWindowManager().lockNow(null); } catch (RemoteException e) { } finally { -- cgit v1.1