summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndres Morales <anmorales@google.com>2015-05-27 18:37:21 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-05-27 18:37:32 +0000
commit5ccfe51d8b9ae4f73a3b0fdb553b807cf5691582 (patch)
tree93187b35ac868eec08498685ad91c2a5ee5272cd
parent77aa9afe0c67ca7285ed81664571f3d6f567eb9b (diff)
parent2397427cb1a0bad8a42e6a342dcf29b31e40a234 (diff)
downloadframeworks_base-5ccfe51d8b9ae4f73a3b0fdb553b807cf5691582.zip
frameworks_base-5ccfe51d8b9ae4f73a3b0fdb553b807cf5691582.tar.gz
frameworks_base-5ccfe51d8b9ae4f73a3b0fdb553b807cf5691582.tar.bz2
Merge "[LockSettings] migrate password attempt throttling to hardware" into mnc-dev
-rw-r--r--core/java/android/service/gatekeeper/GateKeeperResponse.aidl24
-rw-r--r--core/java/android/service/gatekeeper/GateKeeperResponse.java120
-rw-r--r--core/java/android/service/gatekeeper/IGateKeeperService.aidl16
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl10
-rw-r--r--core/java/com/android/internal/widget/LockPatternChecker.java54
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java96
-rw-r--r--core/java/com/android/internal/widget/VerifyCredentialResponse.aidl24
-rw-r--r--core/java/com/android/internal/widget/VerifyCredentialResponse.java126
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java33
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java26
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java4
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java28
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java230
13 files changed, 592 insertions, 199 deletions
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.aidl b/core/java/android/service/gatekeeper/GateKeeperResponse.aidl
new file mode 100644
index 0000000..966606e
--- /dev/null
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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 android.service.gatekeeper;
+
+/**
+ * Response object for a GateKeeper verification request.
+ * @hide
+ */
+parcelable GateKeeperResponse;
+
diff --git a/core/java/android/service/gatekeeper/GateKeeperResponse.java b/core/java/android/service/gatekeeper/GateKeeperResponse.java
new file mode 100644
index 0000000..a512957
--- /dev/null
+++ b/core/java/android/service/gatekeeper/GateKeeperResponse.java
@@ -0,0 +1,120 @@
+/*
+ * 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 android.service.gatekeeper;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Response object for a GateKeeper verification request.
+ * @hide
+ */
+public final class GateKeeperResponse implements Parcelable {
+
+ public static final int RESPONSE_ERROR = -1;
+ public static final int RESPONSE_OK = 0;
+ public static final int RESPONSE_RETRY = 1;
+
+ private final int mResponseCode;
+
+ private int mTimeout;
+ private byte[] mPayload;
+ private boolean mShouldReEnroll;
+
+ private GateKeeperResponse(int responseCode) {
+ mResponseCode = responseCode;
+ }
+
+ private GateKeeperResponse(int responseCode, int timeout) {
+ mResponseCode = responseCode;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<GateKeeperResponse> CREATOR
+ = new Parcelable.Creator<GateKeeperResponse>() {
+ @Override
+ public GateKeeperResponse createFromParcel(Parcel source) {
+ int responseCode = source.readInt();
+ GateKeeperResponse response = new GateKeeperResponse(responseCode);
+ if (responseCode == RESPONSE_RETRY) {
+ response.setTimeout(source.readInt());
+ } else if (responseCode == RESPONSE_OK) {
+ response.setShouldReEnroll(source.readInt() == 1);
+ int size = source.readInt();
+ if (size > 0) {
+ byte[] payload = new byte[size];
+ source.readByteArray(payload);
+ response.setPayload(payload);
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public GateKeeperResponse[] newArray(int size) {
+ return new GateKeeperResponse[size];
+ }
+
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResponseCode);
+ if (mResponseCode == RESPONSE_RETRY) {
+ dest.writeInt(mTimeout);
+ } else if (mResponseCode == RESPONSE_OK) {
+ dest.writeInt(mShouldReEnroll ? 1 : 0);
+ if (mPayload != null) {
+ dest.writeInt(mPayload.length);
+ dest.writeByteArray(mPayload);
+ }
+ }
+ }
+
+ public byte[] getPayload() {
+ return mPayload;
+ }
+
+ public int getTimeout() {
+ return mTimeout;
+ }
+
+ public boolean getShouldReEnroll() {
+ return mShouldReEnroll;
+ }
+
+ public int getResponseCode() {
+ return mResponseCode;
+ }
+
+ private void setTimeout(int timeout) {
+ mTimeout = timeout;
+ }
+
+ private void setShouldReEnroll(boolean shouldReEnroll) {
+ mShouldReEnroll = shouldReEnroll;
+ }
+
+ private void setPayload(byte[] payload) {
+ mPayload = payload;
+ }
+
+}
diff --git a/core/java/android/service/gatekeeper/IGateKeeperService.aidl b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
index 4f46701..6db2110 100644
--- a/core/java/android/service/gatekeeper/IGateKeeperService.aidl
+++ b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
@@ -16,6 +16,8 @@
package android.service.gatekeeper;
+import android.service.gatekeeper.GateKeeperResponse;
+
/**
* Interface for communication with GateKeeper, the
* secure password storage daemon.
@@ -34,9 +36,9 @@ interface IGateKeeperService {
* If provided, must verify against the currentPasswordHandle.
* @param desiredPassword The new desired password, for which a handle will be returned
* upon success.
- * @return the handle corresponding to desiredPassword, or null
+ * @return an EnrollResponse or null on failure
*/
- byte[] enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword,
+ GateKeeperResponse enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword,
in byte[] desiredPassword);
/**
@@ -45,10 +47,10 @@ interface IGateKeeperService {
* @param enrolledPasswordHandle The handle against which the provided password will be
* verified.
* @param The plaintext blob to verify against enrolledPassword.
- * @return True if the authentication was successful
+ * @return a VerifyResponse, or null on failure.
*/
- boolean verify(int uid, in byte[] enrolledPasswordHandle,
- in byte[] providedPassword);
+ GateKeeperResponse verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
+
/**
* Verifies an enrolled handle against a provided, plaintext blob.
* @param uid The Android user ID associated to this enrollment
@@ -58,9 +60,9 @@ interface IGateKeeperService {
* @param enrolledPasswordHandle The handle against which the provided password will be
* verified.
* @param The plaintext blob to verify against enrolledPassword.
- * @return an opaque attestation of authentication on success, or null.
+ * @return a VerifyResponse with an attestation, or null on failure.
*/
- byte[] verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
+ GateKeeperResponse verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
in byte[] providedPassword);
/**
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index bfafff6..dfb7c50 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import com.android.internal.widget.VerifyCredentialResponse;
+
/** {@hide} */
interface ILockSettings {
void setBoolean(in String key, in boolean value, in int userId);
@@ -25,11 +27,11 @@ interface ILockSettings {
long getLong(in String key, in long defaultValue, in int userId);
String getString(in String key, in String defaultValue, in int userId);
void setLockPattern(in String pattern, in String savedPattern, int userId);
- boolean checkPattern(in String pattern, int userId);
- byte[] verifyPattern(in String pattern, long challenge, int userId);
+ VerifyCredentialResponse checkPattern(in String pattern, int userId);
+ VerifyCredentialResponse verifyPattern(in String pattern, long challenge, int userId);
void setLockPassword(in String password, in String savedPassword, int userId);
- boolean checkPassword(in String password, int userId);
- byte[] verifyPassword(in String password, long challenge, int userId);
+ VerifyCredentialResponse checkPassword(in String password, int userId);
+ VerifyCredentialResponse verifyPassword(in String password, long challenge, int userId);
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index ac0f5fe..4880664 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -2,6 +2,8 @@ package com.android.internal.widget;
import android.os.AsyncTask;
+import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
+
import java.util.List;
/**
@@ -16,8 +18,10 @@ public final class LockPatternChecker {
* Invoked when a security check is finished.
*
* @param matched Whether the PIN/Password/Pattern matches the stored one.
+ * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
+ * the call. Only non-0 if matched is false.
*/
- void onChecked(boolean matched);
+ void onChecked(boolean matched, int throttleTimeoutMs);
}
/**
@@ -28,8 +32,10 @@ public final class LockPatternChecker {
* Invoked when a security verification is finished.
*
* @param attestation The attestation that the challenge was verified, or null.
+ * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
+ * the call. Only non-0 if attestation is null.
*/
- void onVerified(byte[] attestation);
+ void onVerified(byte[] attestation, int throttleTimeoutMs);
}
/**
@@ -47,14 +53,21 @@ public final class LockPatternChecker {
final int userId,
final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
+ private int mThrottleTimeout;
+
@Override
protected byte[] doInBackground(Void... args) {
- return utils.verifyPattern(pattern, challenge, userId);
+ try {
+ return utils.verifyPattern(pattern, challenge, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return null;
+ }
}
@Override
protected void onPostExecute(byte[] result) {
- callback.onVerified(result);
+ callback.onVerified(result, mThrottleTimeout);
}
};
task.execute();
@@ -74,14 +87,21 @@ public final class LockPatternChecker {
final int userId,
final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
+ private int mThrottleTimeout;
+
@Override
protected Boolean doInBackground(Void... args) {
- return utils.checkPattern(pattern, userId);
+ try {
+ return utils.checkPattern(pattern, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return false;
+ }
}
@Override
protected void onPostExecute(Boolean result) {
- callback.onChecked(result);
+ callback.onChecked(result, mThrottleTimeout);
}
};
task.execute();
@@ -103,14 +123,21 @@ public final class LockPatternChecker {
final int userId,
final OnVerifyCallback callback) {
AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
+ private int mThrottleTimeout;
+
@Override
protected byte[] doInBackground(Void... args) {
- return utils.verifyPassword(password, challenge, userId);
+ try {
+ return utils.verifyPassword(password, challenge, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return null;
+ }
}
@Override
protected void onPostExecute(byte[] result) {
- callback.onVerified(result);
+ callback.onVerified(result, mThrottleTimeout);
}
};
task.execute();
@@ -130,14 +157,21 @@ public final class LockPatternChecker {
final int userId,
final OnCheckCallback callback) {
AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
+ private int mThrottleTimeout;
+
@Override
protected Boolean doInBackground(Void... args) {
- return utils.checkPassword(password, userId);
+ try {
+ return utils.checkPassword(password, userId);
+ } catch (RequestThrottledException ex) {
+ mThrottleTimeout = ex.getTimeoutMs();
+ return false;
+ }
}
@Override
protected void onPostExecute(Boolean result) {
- callback.onChecked(result);
+ callback.onChecked(result, mThrottleTimeout);
}
};
task.execute();
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 55b058c..aee0ff6 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -60,24 +60,12 @@ public class LockPatternUtils {
private static final boolean DEBUG = false;
/**
- * The maximum number of incorrect attempts before the user is prevented
- * from trying again for {@link #FAILED_ATTEMPT_TIMEOUT_MS}.
- */
- public static final int FAILED_ATTEMPTS_BEFORE_TIMEOUT = 5;
-
- /**
* The number of incorrect attempts before which we fall back on an alternative
* method of verifying the user, and resetting their lock pattern.
*/
public static final int FAILED_ATTEMPTS_BEFORE_RESET = 20;
/**
- * How long the user is prevented from trying again after entering the
- * wrong pattern too many times.
- */
- public static final long FAILED_ATTEMPT_TIMEOUT_MS = 30000L;
-
- /**
* The interval of the countdown for showing progress of the lockout.
*/
public static final long FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS = 1000L;
@@ -109,6 +97,7 @@ public class LockPatternUtils {
@Deprecated
public final static String LOCKOUT_PERMANENT_KEY = "lockscreen.lockedoutpermanently";
public final static String LOCKOUT_ATTEMPT_DEADLINE = "lockscreen.lockoutattemptdeadline";
+ public final static String LOCKOUT_ATTEMPT_TIMEOUT_MS = "lockscreen.lockoutattempttimeoutmss";
public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
@@ -144,6 +133,23 @@ public class LockPatternUtils {
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
+
+ public static final class RequestThrottledException extends Exception {
+ private int mTimeoutMs;
+ public RequestThrottledException(int timeoutMs) {
+ mTimeoutMs = timeoutMs;
+ }
+
+ /**
+ * @return The amount of time in ms before another request may
+ * be executed
+ */
+ public int getTimeoutMs() {
+ return mTimeoutMs;
+ }
+
+ }
+
public DevicePolicyManager getDevicePolicyManager() {
if (mDevicePolicyManager == null) {
mDevicePolicyManager =
@@ -239,9 +245,23 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the pattern
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId) {
+ public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+ if (response == null) {
+ // Shouldn't happen
+ return null;
+ }
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return response.getPayload();
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return null;
+ }
} catch (RemoteException re) {
return null;
}
@@ -253,9 +273,19 @@ public class LockPatternUtils {
* @param pattern The pattern to check.
* @return Whether the pattern matches the stored one.
*/
- public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId) {
+ public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().checkPattern(patternToString(pattern), userId);
+ VerifyCredentialResponse response =
+ getLockSettings().checkPattern(patternToString(pattern), userId);
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return true;
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return false;
+ }
} catch (RemoteException re) {
return true;
}
@@ -270,9 +300,19 @@ public class LockPatternUtils {
* @param challenge The challenge to verify against the password
* @return the attestation that the challenge was verified, or null.
*/
- public byte[] verifyPassword(String password, long challenge, int userId) {
+ public byte[] verifyPassword(String password, long challenge, int userId)
+ throws RequestThrottledException {
try {
- return getLockSettings().verifyPassword(password, challenge, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().verifyPassword(password, challenge, userId);
+
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return response.getPayload();
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return null;
+ }
} catch (RemoteException re) {
return null;
}
@@ -284,9 +324,17 @@ public class LockPatternUtils {
* @param password The password to check.
* @return Whether the password matches the stored one.
*/
- public boolean checkPassword(String password, int userId) {
+ public boolean checkPassword(String password, int userId) throws RequestThrottledException {
try {
- return getLockSettings().checkPassword(password, userId);
+ VerifyCredentialResponse response =
+ getLockSettings().checkPassword(password, userId);
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ return true;
+ } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+ throw new RequestThrottledException(response.getTimeout());
+ } else {
+ return false;
+ }
} catch (RemoteException re) {
return true;
}
@@ -992,9 +1040,10 @@ public class LockPatternUtils {
* pattern until the deadline has passed.
* @return the chosen deadline.
*/
- public long setLockoutAttemptDeadline(int userId) {
- final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
+ public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
+ final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
setLong(LOCKOUT_ATTEMPT_DEADLINE, deadline, userId);
+ setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, timeoutMs, userId);
return deadline;
}
@@ -1005,8 +1054,9 @@ public class LockPatternUtils {
*/
public long getLockoutAttemptDeadline(int userId) {
final long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
+ final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
final long now = SystemClock.elapsedRealtime();
- if (deadline < now || deadline > (now + FAILED_ATTEMPT_TIMEOUT_MS)) {
+ if (deadline < now || deadline > (now + timeoutMs)) {
return 0L;
}
return deadline;
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl
new file mode 100644
index 0000000..59a4bba
--- /dev/null
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.internal.widget;
+
+/**
+ * Response object for an ILockSettings verification request.
+ * @hide
+ */
+parcelable VerifyCredentialResponse;
+
diff --git a/core/java/com/android/internal/widget/VerifyCredentialResponse.java b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
new file mode 100644
index 0000000..48109ca
--- /dev/null
+++ b/core/java/com/android/internal/widget/VerifyCredentialResponse.java
@@ -0,0 +1,126 @@
+/*
+ * 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.internal.widget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Response object for a ILockSettings credential verification request.
+ * @hide
+ */
+public final class VerifyCredentialResponse implements Parcelable {
+
+ public static final int RESPONSE_ERROR = -1;
+ public static final int RESPONSE_OK = 0;
+ public static final int RESPONSE_RETRY = 1;
+
+ public static final VerifyCredentialResponse OK = new VerifyCredentialResponse();
+ public static final VerifyCredentialResponse ERROR
+ = new VerifyCredentialResponse(RESPONSE_ERROR, 0, null);
+
+ private int mResponseCode;
+ private byte[] mPayload;
+ private int mTimeout;
+
+ public static final Parcelable.Creator<VerifyCredentialResponse> CREATOR
+ = new Parcelable.Creator<VerifyCredentialResponse>() {
+ @Override
+ public VerifyCredentialResponse createFromParcel(Parcel source) {
+ int responseCode = source.readInt();
+ VerifyCredentialResponse response = new VerifyCredentialResponse(responseCode, 0, null);
+ if (responseCode == RESPONSE_RETRY) {
+ response.setTimeout(source.readInt());
+ } else if (responseCode == RESPONSE_OK) {
+ int size = source.readInt();
+ if (size > 0) {
+ byte[] payload = new byte[size];
+ source.readByteArray(payload);
+ response.setPayload(payload);
+ }
+ }
+ return response;
+ }
+
+ @Override
+ public VerifyCredentialResponse[] newArray(int size) {
+ return new VerifyCredentialResponse[size];
+ }
+
+ };
+
+ public VerifyCredentialResponse() {
+ mResponseCode = RESPONSE_OK;
+ mPayload = null;
+ }
+
+
+ public VerifyCredentialResponse(byte[] payload) {
+ mPayload = payload;
+ mResponseCode = RESPONSE_OK;
+ }
+
+ public VerifyCredentialResponse(int timeout) {
+ mTimeout = timeout;
+ mResponseCode = RESPONSE_RETRY;
+ mPayload = null;
+ }
+
+ private VerifyCredentialResponse(int responseCode, int timeout, byte[] payload) {
+ mResponseCode = responseCode;
+ mTimeout = timeout;
+ mPayload = payload;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResponseCode);
+ if (mResponseCode == RESPONSE_RETRY) {
+ dest.writeInt(mTimeout);
+ } else if (mResponseCode == RESPONSE_OK) {
+ if (mPayload != null) {
+ dest.writeInt(mPayload.length);
+ dest.writeByteArray(mPayload);
+ }
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public byte[] getPayload() {
+ return mPayload;
+ }
+
+ public int getTimeout() {
+ return mTimeout;
+ }
+
+ public int getResponseCode() {
+ return mResponseCode;
+ }
+
+ private void setTimeout(int timeout) {
+ mTimeout = timeout;
+ }
+
+ private void setPayload(byte[] payload) {
+ mPayload = payload;
+ }
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index 6295de4..4edc1c9 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -114,35 +114,40 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
}
+
+ if (entry.length() < MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) {
+ // to avoid accidental lockout, only count attempts that are long enough to be a
+ // real password. This may require some tweaking.
+ setPasswordEntryInputEnabled(true);
+ onPasswordChecked(entry, false, 0);
+ return;
+ }
+
mPendingLockCheck = LockPatternChecker.checkPassword(
mLockPatternUtils,
entry,
KeyguardUpdateMonitor.getCurrentUser(),
new LockPatternChecker.OnCheckCallback() {
@Override
- public void onChecked(boolean matched) {
+ public void onChecked(boolean matched, int timeoutMs) {
setPasswordEntryInputEnabled(true);
mPendingLockCheck = null;
- onPasswordChecked(entry, matched);
+ onPasswordChecked(entry, matched, timeoutMs);
}
});
}
- private void onPasswordChecked(String entry, boolean matched) {
+ private void onPasswordChecked(String entry, boolean matched, int timeoutMs) {
if (matched) {
- mCallback.reportUnlockAttempt(true);
+ mCallback.reportUnlockAttempt(true, 0);
mCallback.dismiss(true);
} else {
- if (entry.length() > MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT ) {
- // to avoid accidental lockout, only count attempts that are long enough to be a
- // real password. This may require some tweaking.
- mCallback.reportUnlockAttempt(false);
- int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
- if (0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
- long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
- handleAttemptLockout(deadline);
- }
+ mCallback.reportUnlockAttempt(false, timeoutMs);
+ int attempts = KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts();
+ if (timeoutMs > 0) {
+ long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
+ KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
+ handleAttemptLockout(deadline);
}
mSecurityMessageDisplay.setMessage(getWrongPasswordStringId(), true);
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 35c6873..ed595c0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -224,23 +224,30 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mPendingLockCheck.cancel(false);
}
+ if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
+ mLockPatternView.enableInput();
+ onPatternChecked(pattern, false, 0);
+ return;
+ }
+
mPendingLockCheck = LockPatternChecker.checkPattern(
mLockPatternUtils,
pattern,
KeyguardUpdateMonitor.getCurrentUser(),
new LockPatternChecker.OnCheckCallback() {
@Override
- public void onChecked(boolean matched) {
+ public void onChecked(boolean matched, int timeoutMs) {
mLockPatternView.enableInput();
mPendingLockCheck = null;
- onPatternChecked(pattern, matched);
+ onPatternChecked(pattern, matched, timeoutMs);
}
});
}
- private void onPatternChecked(List<LockPatternView.Cell> pattern, boolean matched) {
+ private void onPatternChecked(List<LockPatternView.Cell> pattern, boolean matched,
+ int timeoutMs) {
if (matched) {
- mCallback.reportUnlockAttempt(true);
+ mCallback.reportUnlockAttempt(true, 0);
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
mCallback.dismiss(true);
} else {
@@ -248,16 +255,11 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mCallback.userActivity();
}
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
- boolean registeredAttempt =
- pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL;
- if (registeredAttempt) {
- mCallback.reportUnlockAttempt(false);
- }
+ mCallback.reportUnlockAttempt(false, timeoutMs);
int attempts = mKeyguardUpdateMonitor.getFailedUnlockAttempts();
- if (registeredAttempt &&
- 0 == (attempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
+ if (timeoutMs > 0) {
long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
- KeyguardUpdateMonitor.getCurrentUser());
+ KeyguardUpdateMonitor.getCurrentUser(), timeoutMs);
handleAttemptLockout(deadline);
} else {
mSecurityMessageDisplay.setMessage(R.string.kg_wrong_pattern, true);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
index 5877bc8..836c195 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityCallback.java
@@ -37,8 +37,10 @@ public interface KeyguardSecurityCallback {
/**
* Call to report an unlock attempt.
* @param success set to 'true' if user correctly entered security credentials.
+ * @param timeoutMs timeout in milliseconds to wait before reattempting an unlock.
+ * Only nonzero if 'success' is false
*/
- void reportUnlockAttempt(boolean success);
+ void reportUnlockAttempt(boolean success, int timeoutMs);
/**
* Resets the keyguard view.
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 4d89a8d..d17b25a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -176,8 +176,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
dialog.show();
}
- private void showTimeoutDialog() {
- int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
+ private void showTimeoutDialog(int timeoutMs) {
+ int timeoutInSeconds = (int) timeoutMs / 1000;
int messageId = 0;
switch (mSecurityModel.getSecurityMode()) {
@@ -244,16 +244,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
showDialog(null, message);
}
- private void showAlmostAtAccountLoginDialog() {
- final int timeoutInSeconds = (int) LockPatternUtils.FAILED_ATTEMPT_TIMEOUT_MS / 1000;
- final int count = LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
- - LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT;
- String message = mContext.getString(R.string.kg_failed_attempts_almost_at_login,
- count, LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT, timeoutInSeconds);
- showDialog(null, message);
- }
-
- private void reportFailedUnlockAttempt() {
+ private void reportFailedUnlockAttempt(int timeoutMs) {
final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
final int failedAttempts = monitor.getFailedUnlockAttempts() + 1; // +1 for this time
@@ -290,14 +281,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
Slog.i(TAG, "Too many unlock attempts; user " + expiringUser + " will be wiped!");
showWipeDialog(failedAttempts, userType);
}
- } else {
- showTimeout =
- (failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) == 0;
}
monitor.reportFailedUnlockAttempt();
mLockPatternUtils.reportFailedPasswordAttempt(KeyguardUpdateMonitor.getCurrentUser());
- if (showTimeout) {
- showTimeoutDialog();
+ if (timeoutMs > 0) {
+ showTimeoutDialog(timeoutMs);
}
}
@@ -425,14 +413,14 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
return mIsVerifyUnlockOnly;
}
- public void reportUnlockAttempt(boolean success) {
+ public void reportUnlockAttempt(boolean success, int timeoutMs) {
KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
if (success) {
monitor.clearFailedUnlockAttempts();
mLockPatternUtils.reportSuccessfulPasswordAttempt(
KeyguardUpdateMonitor.getCurrentUser());
} else {
- KeyguardSecurityContainer.this.reportFailedUnlockAttempt();
+ KeyguardSecurityContainer.this.reportFailedUnlockAttempt(timeoutMs);
}
}
@@ -448,7 +436,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
@Override
public void userActivity() { }
@Override
- public void reportUnlockAttempt(boolean success) { }
+ public void reportUnlockAttempt(boolean success, int timeoutMs) { }
@Override
public boolean isVerifyUnlockOnly() { return false; }
@Override
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 2df7f79..f6ca0d7 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -25,11 +25,9 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-
import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
import static android.content.Context.USER_SERVICE;
import static android.Manifest.permission.READ_PROFILE;
-
import android.database.sqlite.SQLiteDatabase;
import android.os.Binder;
import android.os.IBinder;
@@ -44,6 +42,7 @@ import android.provider.Settings;
import android.provider.Settings.Secure;
import android.provider.Settings.SettingNotFoundException;
import android.security.KeyStore;
+import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
import android.util.Slog;
@@ -51,6 +50,7 @@ import android.util.Slog;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ILockSettings;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.LockSettingsStorage.CredentialHash;
import java.util.Arrays;
@@ -76,6 +76,12 @@ public class LockSettingsService extends ILockSettings.Stub {
private boolean mFirstCallToVold;
private IGateKeeperService mGateKeeperService;
+ private interface CredentialUtil {
+ void setCredential(String credential, String savedCredential, int userId)
+ throws RemoteException;
+ byte[] toHash(String credential, int userId);
+ }
+
public LockSettingsService(Context context) {
mContext = context;
// Open the database
@@ -468,155 +474,163 @@ public class LockSettingsService extends ILockSettings.Stub {
byte[] toEnrollBytes = toEnroll == null
? null
: toEnroll.getBytes();
- byte[] hash = getGateKeeperService().enroll(userId, enrolledHandle, enrolledCredentialBytes,
- toEnrollBytes);
+ GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
+ enrolledCredentialBytes, toEnrollBytes);
+ if (response == null) {
+ return null;
+ }
+
+ byte[] hash = response.getPayload();
if (hash != null) {
setKeystorePassword(toEnroll, userId);
+ } else {
+ // Should not happen
+ Slog.e(TAG, "Throttled while enrolling a password");
}
-
return hash;
}
@Override
- public boolean checkPattern(String pattern, int userId) throws RemoteException {
- try {
- doVerifyPattern(pattern, false, 0, userId);
- } catch (VerificationFailedException ex) {
- return false;
- }
-
- return true;
+ public VerifyCredentialResponse checkPattern(String pattern, int userId) throws RemoteException {
+ return doVerifyPattern(pattern, false, 0, userId);
}
@Override
- public byte[] verifyPattern(String pattern, long challenge, int userId)
+ public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
throws RemoteException {
- try {
- return doVerifyPattern(pattern, true, challenge, userId);
- } catch (VerificationFailedException ex) {
- return null;
- }
+ return doVerifyPattern(pattern, true, challenge, userId);
}
- private byte[] doVerifyPattern(String pattern, boolean hasChallenge, long challenge,
- int userId) throws VerificationFailedException, RemoteException {
+ private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge, long challenge,
+ int userId) throws RemoteException {
checkPasswordReadPermission(userId);
-
CredentialHash storedHash = mStorage.readPatternHash(userId);
-
- if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(pattern)) {
- // don't need to pass empty passwords to GateKeeper
- return null;
- }
-
- if (TextUtils.isEmpty(pattern)) {
- throw new VerificationFailedException();
- }
-
- if (storedHash.version == CredentialHash.VERSION_LEGACY) {
- byte[] hash = mLockPatternUtils.patternToHash(
- mLockPatternUtils.stringToPattern(pattern));
- if (Arrays.equals(hash, storedHash.hash)) {
- unlockKeystore(pattern, userId);
- // migrate password to GateKeeper
- setLockPattern(pattern, null, userId);
- if (!hasChallenge) {
- return null;
- }
- // Fall through to get the auth token. Technically this should never happen,
- // as a user that had a legacy pattern would have to unlock their device
- // before getting to a flow with a challenge, but supporting for consistency.
- } else {
- throw new VerificationFailedException();
- }
- }
-
- byte[] token = null;
- if (hasChallenge) {
- token = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, pattern.getBytes());
- if (token == null) {
- throw new VerificationFailedException();
- }
- } else if (!getGateKeeperService().verify(userId, storedHash.hash, pattern.getBytes())) {
- throw new VerificationFailedException();
- }
-
- // pattern has matched
- unlockKeystore(pattern, userId);
- return token;
-
+ return verifyCredential(userId, storedHash, pattern, hasChallenge,
+ challenge,
+ new CredentialUtil() {
+ @Override
+ public void setCredential(String pattern, String oldPattern, int userId)
+ throws RemoteException {
+ setLockPattern(pattern, oldPattern, userId);
+ }
+
+ @Override
+ public byte[] toHash(String pattern, int userId) {
+ return mLockPatternUtils.patternToHash(
+ mLockPatternUtils.stringToPattern(pattern));
+ }
+ }
+ );
}
@Override
- public boolean checkPassword(String password, int userId) throws RemoteException {
- try {
- doVerifyPassword(password, false, 0, userId);
- } catch (VerificationFailedException ex) {
- return false;
- }
- return true;
+ public VerifyCredentialResponse checkPassword(String password, int userId)
+ throws RemoteException {
+ return doVerifyPassword(password, false, 0, userId);
}
@Override
- public byte[] verifyPassword(String password, long challenge, int userId)
+ public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
throws RemoteException {
- try {
- return doVerifyPassword(password, true, challenge, userId);
- } catch (VerificationFailedException ex) {
- return null;
- }
+ return doVerifyPassword(password, true, challenge, userId);
}
- private byte[] doVerifyPassword(String password, boolean hasChallenge, long challenge,
- int userId) throws VerificationFailedException, RemoteException {
+ private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
+ long challenge, int userId) throws RemoteException {
checkPasswordReadPermission(userId);
-
CredentialHash storedHash = mStorage.readPasswordHash(userId);
+ return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
+ new CredentialUtil() {
+ @Override
+ public void setCredential(String password, String oldPassword, int userId)
+ throws RemoteException {
+ setLockPassword(password, oldPassword, userId);
+ }
- if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(password)) {
- // don't need to pass empty passwords to GateKeeper
- return null;
+ @Override
+ public byte[] toHash(String password, int userId) {
+ return mLockPatternUtils.passwordToHash(password, userId);
+ }
+ }
+ );
+ }
+
+ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
+ String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil)
+ throws RemoteException {
+ if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
+ // don't need to pass empty credentials to GateKeeper
+ return VerifyCredentialResponse.OK;
}
- if (TextUtils.isEmpty(password)) {
- throw new VerificationFailedException();
+ if (TextUtils.isEmpty(credential)) {
+ return VerifyCredentialResponse.ERROR;
}
if (storedHash.version == CredentialHash.VERSION_LEGACY) {
- byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
+ byte[] hash = credentialUtil.toHash(credential, userId);
if (Arrays.equals(hash, storedHash.hash)) {
- unlockKeystore(password, userId);
- // migrate password to GateKeeper
- setLockPassword(password, null, userId);
+ unlockKeystore(credential, userId);
+ // migrate credential to GateKeeper
+ credentialUtil.setCredential(credential, null, userId);
if (!hasChallenge) {
- return null;
+ return VerifyCredentialResponse.OK;
}
// Fall through to get the auth token. Technically this should never happen,
- // as a user that had a legacy password would have to unlock their device
+ // as a user that had a legacy credential would have to unlock their device
// before getting to a flow with a challenge, but supporting for consistency.
} else {
- throw new VerificationFailedException();
+ return VerifyCredentialResponse.ERROR;
}
}
- byte[] token = null;
+ VerifyCredentialResponse response;
+ boolean shouldReEnroll = false;;
if (hasChallenge) {
- token = getGateKeeperService()
- .verifyChallenge(userId, challenge, storedHash.hash, password.getBytes());
- if (token == null) {
- throw new VerificationFailedException();
+ byte[] token = null;
+ GateKeeperResponse gateKeeperResponse = getGateKeeperService()
+ .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
+ int responseCode = gateKeeperResponse.getResponseCode();
+ if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
+ response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
+ } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
+ token = gateKeeperResponse.getPayload();
+ if (token == null) {
+ // something's wrong if there's no payload with a challenge
+ Slog.e(TAG, "verifyChallenge response had no associated payload");
+ response = VerifyCredentialResponse.ERROR;
+ } else {
+ shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
+ response = new VerifyCredentialResponse(token);
+ }
+ } else {
+ response = VerifyCredentialResponse.ERROR;
+ }
+ } else {
+ GateKeeperResponse gateKeeperResponse = getGateKeeperService().verify(
+ userId, storedHash.hash, credential.getBytes());
+ int responseCode = gateKeeperResponse.getResponseCode();
+ if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
+ response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
+ } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
+ shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
+ response = VerifyCredentialResponse.OK;
+ } else {
+ response = VerifyCredentialResponse.ERROR;
}
- } else if (!getGateKeeperService().verify(userId, storedHash.hash, password.getBytes())) {
- throw new VerificationFailedException();
}
- // password has matched
- unlockKeystore(password, userId);
- return token;
- }
+ if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
+ // credential has matched
+ unlockKeystore(credential, userId);
+ if (shouldReEnroll) {
+ credentialUtil.setCredential(credential, credential, userId);
+ }
+ }
+ return response;
+ }
@Override
public boolean checkVoldPassword(int userId) throws RemoteException {
@@ -644,7 +658,8 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
if (mLockPatternUtils.isLockPatternEnabled(userId)) {
- if (checkPattern(password, userId)) {
+ if (checkPattern(password, userId).getResponseCode()
+ == GateKeeperResponse.RESPONSE_OK) {
return true;
}
}
@@ -653,7 +668,8 @@ public class LockSettingsService extends ILockSettings.Stub {
try {
if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
- if (checkPassword(password, userId)) {
+ if (checkPassword(password, userId).getResponseCode()
+ == GateKeeperResponse.RESPONSE_OK) {
return true;
}
}
@@ -741,6 +757,4 @@ public class LockSettingsService extends ILockSettings.Stub {
return null;
}
- private class VerificationFailedException extends Exception {}
-
}