diff options
author | Jorim Jaggi <jjaggi@google.com> | 2015-08-13 01:09:21 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-08-13 01:09:21 +0000 |
commit | deb6a3acbdbf81a995cc3c1eb2475b041564d44d (patch) | |
tree | 7e99b0056b85682e7d05f57942566b93b56dc9e8 /packages/Keyguard | |
parent | 40bc20660d3dc65f66e4409893f1ba6bf729d97f (diff) | |
parent | 73d9e1ce0bc8e4478b165fd5f550c99830fbcb57 (diff) | |
download | frameworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.zip frameworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.tar.gz frameworks_base-deb6a3acbdbf81a995cc3c1eb2475b041564d44d.tar.bz2 |
am 73d9e1ce: am 69082a29: Merge "Require strong authentication after a timeout" into mnc-dr-dev
* commit '73d9e1ce0bc8e4478b165fd5f550c99830fbcb57':
Require strong authentication after a timeout
Diffstat (limited to 'packages/Keyguard')
10 files changed, 132 insertions, 47 deletions
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml index 41b1059..d1e84f5 100644 --- a/packages/Keyguard/res/values/strings.xml +++ b/packages/Keyguard/res/values/strings.xml @@ -316,6 +316,15 @@ <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=80] --> <string name="kg_prompt_reason_restart_password">Password required when you restart device.</string> + <!-- An explanation text that the pattern needs to be solved since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] --> + <string name="kg_prompt_reason_timeout_pattern">Pattern required for additional security.</string> + + <!-- An explanation text that the pin needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] --> + <string name="kg_prompt_reason_timeout_pin">PIN required for additional security.</string> + + <!-- An explanation text that the password needs to be entered since the user hasn't used strong authentication since quite some time. [CHAR LIMIT=80] --> + <string name="kg_prompt_reason_timeout_password">Password required for additional security.</string> + <!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] --> <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles.</string> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java index 32892cf..ec2a173 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardHostView.java @@ -163,8 +163,9 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { * Show a string explaining why the security view needs to be solved. * * @param reason a flag indicating which string should be shown, see - * {@link KeyguardSecurityView#PROMPT_REASON_NONE} - * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART} + * {@link KeyguardSecurityView#PROMPT_REASON_NONE}, + * {@link KeyguardSecurityView#PROMPT_REASON_RESTART} and + * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}. */ public void showPromptReason(int reason) { mSecurityContainer.showPromptReason(reason); @@ -213,9 +214,12 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { /** * Authentication has happened and it's time to dismiss keyguard. This function * should clean up and inform KeyguardViewMediator. + * + * @param strongAuth whether the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint */ @Override - public void finish() { + public void finish(boolean strongAuth) { // If there's a pending runnable because the user interacted with a widget // and we're leaving keyguard, then run it. boolean deferKeyguardDone = false; @@ -226,9 +230,9 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { } if (mViewMediatorCallback != null) { if (deferKeyguardDone) { - mViewMediatorCallback.keyguardDonePending(); + mViewMediatorCallback.keyguardDonePending(strongAuth); } else { - mViewMediatorCallback.keyguardDone(true); + mViewMediatorCallback.keyguardDone(strongAuth); } } } @@ -285,32 +289,6 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback { } /** - * Verify that the user can get past the keyguard securely. This is called, - * for example, when the phone disables the keyguard but then wants to launch - * something else that requires secure access. - * - * The result will be propogated back via {@link KeyguardViewCallback#keyguardDone(boolean)} - */ - public void verifyUnlock() { - SecurityMode securityMode = mSecurityContainer.getSecurityMode(); - if (securityMode == KeyguardSecurityModel.SecurityMode.None) { - if (mViewMediatorCallback != null) { - mViewMediatorCallback.keyguardDone(true); - } - } else if (securityMode != KeyguardSecurityModel.SecurityMode.Pattern - && securityMode != KeyguardSecurityModel.SecurityMode.PIN - && securityMode != KeyguardSecurityModel.SecurityMode.Password) { - // can only verify unlock when in pattern/password mode - if (mViewMediatorCallback != null) { - mViewMediatorCallback.keyguardDone(false); - } - } else { - // otherwise, go to the unlock screen, see if they can verify it - mSecurityContainer.verifyUnlock(); - } - } - - /** * Called before this view is being removed. */ public void cleanUp() { diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java index 2db87b3..3a7e6d0 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java @@ -115,6 +115,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView switch (reason) { case PROMPT_REASON_RESTART: return R.string.kg_prompt_reason_restart_password; + case PROMPT_REASON_TIMEOUT: + return R.string.kg_prompt_reason_timeout_password; default: return 0; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java index a96c79f..9a91ca4 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java @@ -332,7 +332,12 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_restart_pattern, true /* important */); break; + case PROMPT_REASON_TIMEOUT: + mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern, + true /* important */); + break; default: + break; } } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java index 07947b1..4cd4845 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -98,6 +98,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView switch (reason) { case PROMPT_REASON_RESTART: return R.string.kg_prompt_reason_restart_pin; + case PROMPT_REASON_TIMEOUT: + return R.string.kg_prompt_reason_timeout_pin; default: return 0; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java index 8fc3cde..77215a7 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -54,7 +54,12 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe public boolean dismiss(boolean authenticated); public void userActivity(); public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); - public void finish(); + + /** + * @param strongAuth wheher the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint + */ + public void finish(boolean strongAuth); public void reset(); } @@ -282,7 +287,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe showWipeDialog(failedAttempts, userType); } } - monitor.reportFailedUnlockAttempt(); + monitor.reportFailedStrongAuthUnlockAttempt(); mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser()); if (timeoutMs > 0) { showTimeoutDialog(timeoutMs); @@ -308,6 +313,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe boolean showNextSecurityScreenOrFinish(boolean authenticated) { if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); boolean finish = false; + boolean strongAuth = false; if (mUpdateMonitor.getUserCanSkipBouncer( KeyguardUpdateMonitor.getCurrentUser())) { finish = true; @@ -323,6 +329,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe case Pattern: case Password: case PIN: + strongAuth = true; finish = true; break; @@ -346,7 +353,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe } } if (finish) { - mSecurityCallback.finish(); + mSecurityCallback.finish(strongAuth); } return finish; } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java index 7e82c63..38302fb 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityView.java @@ -22,9 +22,18 @@ public interface KeyguardSecurityView { static public final int VIEW_REVEALED = 2; int PROMPT_REASON_NONE = 0; + + /** + * Strong auth is required because the device has just booted. + */ int PROMPT_REASON_RESTART = 1; /** + * Strong auth is required because the user hasn't used strong auth since a while. + */ + int PROMPT_REASON_TIMEOUT = 2; + + /** * Interface back to keyguard to tell it when security * @param callback */ diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index 0ee68fd..3232f65 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -64,6 +64,7 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; import android.telephony.TelephonyManager; +import android.util.ArraySet; import android.util.Log; import android.util.SparseBooleanArray; import android.util.SparseIntArray; @@ -103,6 +104,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { = "com.android.facelock.FACE_UNLOCK_STOPPED"; private static final String FINGERPRINT_WAKE_LOCK_NAME = "wake-and-unlock wakelock"; + private static final String ACTION_STRONG_AUTH_TIMEOUT = + "com.android.systemui.ACTION_STRONG_AUTH_TIMEOUT"; + private static final String USER_ID = "com.android.systemui.USER_ID"; + + private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; + /** * Mode in which we don't need to wake up the device when we get a fingerprint. */ @@ -126,6 +133,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { * */ private static final int FP_ONLY_WAKE = 3; + /** + * Milliseconds after unlocking with fingerprint times out, i.e. the user has to use a + * strong auth method like password, PIN or pattern. + */ + private static final long FINGERPRINT_UNLOCK_TIMEOUT_MS = 72 * 60 * 60 * 1000; + // Callback messages private static final int MSG_TIME_UPDATE = 301; private static final int MSG_BATTERY_UPDATE = 302; @@ -173,7 +186,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { // Password attempts private SparseIntArray mFailedAttempts = new SparseIntArray(); - private boolean mClockVisible; + /** Tracks whether strong authentication hasn't been used since quite some time per user. */ + private ArraySet<Integer> mStrongAuthTimedOut = new ArraySet<>(); private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>> mCallbacks = Lists.newArrayList(); @@ -184,6 +198,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private boolean mDeviceInteractive; private boolean mScreenOn; private SubscriptionManager mSubscriptionManager; + private AlarmManager mAlarmManager; private List<SubscriptionInfo> mSubscriptionInfo; private boolean mFingerprintDetectionRunning; private TrustManager mTrustManager; @@ -549,7 +564,39 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } public boolean isUnlockingWithFingerprintAllowed() { - return mUserHasAuthenticatedSinceBoot; + return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser); + } + + /** + * @return true if the user hasn't use strong authentication (pattern, PIN, password) since a + * while and thus can't unlock with fingerprint, false otherwise + */ + public boolean hasFingerprintUnlockTimedOut(int userId) { + return mStrongAuthTimedOut.contains(userId); + } + + public void reportSuccessfulStrongAuthUnlockAttempt() { + mStrongAuthTimedOut.remove(sCurrentUser); + scheduleStrongAuthTimeout(); + } + + private void scheduleStrongAuthTimeout() { + long when = SystemClock.elapsedRealtime() + FINGERPRINT_UNLOCK_TIMEOUT_MS; + Intent intent = new Intent(ACTION_STRONG_AUTH_TIMEOUT); + intent.putExtra(USER_ID, sCurrentUser); + PendingIntent sender = PendingIntent.getBroadcast(mContext, + sCurrentUser, intent, PendingIntent.FLAG_CANCEL_CURRENT); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, sender); + notifyStrongAuthTimedOutChanged(sCurrentUser); + } + + private void notifyStrongAuthTimedOutChanged(int userId) { + for (int i = 0; i < mCallbacks.size(); i++) { + KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); + if (cb != null) { + cb.onStrongAuthTimeoutExpiredChanged(userId); + } + } } static class DisplayClientState { @@ -639,6 +686,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } }; + private final BroadcastReceiver mStrongAuthTimeoutReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) { + int userId = intent.getIntExtra(USER_ID, -1); + mStrongAuthTimedOut.add(userId); + notifyStrongAuthTimedOutChanged(userId); + } + } + }; + private FingerprintManager.AuthenticationCallback mAuthenticationCallback = new AuthenticationCallback() { @@ -871,7 +929,9 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { mContext = context; mSubscriptionManager = SubscriptionManager.from(context); mPowerManager = context.getSystemService(PowerManager.class); + mAlarmManager = context.getSystemService(AlarmManager.class); mDeviceProvisioned = isDeviceProvisionedInSettingsDb(); + // Since device can't be un-provisioned, we only need to register a content observer // to update mDeviceProvisioned when we are... if (!mDeviceProvisioned) { @@ -932,6 +992,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { e.printStackTrace(); } + IntentFilter strongAuthTimeoutFilter = new IntentFilter(); + strongAuthTimeoutFilter.addAction(ACTION_STRONG_AUTH_TIMEOUT); + context.registerReceiver(mStrongAuthTimeoutReceiver, strongAuthTimeoutFilter, + PERMISSION_SELF, null /* handler */); mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); mTrustManager.registerTrustListener(this); @@ -955,7 +1019,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private void startListeningForFingerprint() { if (DEBUG) Log.v(TAG, "startListeningForFingerprint()"); int userId = ActivityManager.getCurrentUser(); - if (isUnlockWithFingerPrintPossible(userId)) { + if (isUnlockWithFingerprintPossible(userId)) { mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot( ActivityManager.getCurrentUser()); if (mFingerprintCancelSignal != null) { @@ -967,7 +1031,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } } - public boolean isUnlockWithFingerPrintPossible(int userId) { + public boolean isUnlockWithFingerprintPossible(int userId) { return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId) && mFpm.getEnrolledFingerprints(userId).size() > 0; } @@ -1433,7 +1497,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { return mFailedAttempts.get(sCurrentUser, 0); } - public void reportFailedUnlockAttempt() { + public void reportFailedStrongAuthUnlockAttempt() { mFailedAttempts.put(sCurrentUser, getFailedUnlockAttempts() + 1); } diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java index 6cda2b7..52412f7 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java @@ -217,4 +217,10 @@ public class KeyguardUpdateMonitorCallback { * Called when the fingerprint running state changed. */ public void onFingerprintRunningStateChanged(boolean running) { } + + /** + * Called when the state that the user hasn't used strong authentication since quite some time + * has changed. + */ + public void onStrongAuthTimeoutExpiredChanged(int userId) { } } diff --git a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java index ff463c6..8ab3011 100644 --- a/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java +++ b/packages/Keyguard/src/com/android/keyguard/ViewMediatorCallback.java @@ -28,12 +28,11 @@ public interface ViewMediatorCallback { /** * Report that the keyguard is done. - * @param authenticated Whether the user securely got past the keyguard. - * the only reason for this to be false is if the keyguard was instructed - * to appear temporarily to verify the user is supposed to get past the - * keyguard, and the user fails to do so. + * + * @param strongAuth whether the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint */ - void keyguardDone(boolean authenticated); + void keyguardDone(boolean strongAuth); /** * Report that the keyguard is done drawing. @@ -48,8 +47,11 @@ public interface ViewMediatorCallback { /** * Report that the keyguard is dismissable, pending the next keyguardDone call. + * + * @param strongAuth whether the user has authenticated with strong authentication like + * pattern, password or PIN but not by trust agents or fingerprint */ - void keyguardDonePending(); + void keyguardDonePending(boolean strongAuth); /** * Report when keyguard is actually gone @@ -85,8 +87,9 @@ public interface ViewMediatorCallback { /** * @return one of the reasons why the bouncer needs to be shown right now and the user can't use * his normal unlock method like fingerprint or trust agents. See - * {@link KeyguardSecurityView#PROMPT_REASON_NONE} - * and {@link KeyguardSecurityView#PROMPT_REASON_RESTART}. + * {@link KeyguardSecurityView#PROMPT_REASON_NONE}, + * {@link KeyguardSecurityView#PROMPT_REASON_RESTART} and + * {@link KeyguardSecurityView#PROMPT_REASON_TIMEOUT}. */ int getBouncerPromptReason(); } |