Fix races in ConfirmPassword/Pattern

- Add a CheckLockResultTracker to track result of async lock check so that
  it can finish on configuration change;
- Let the pending lock check finish and ignore subsequent check requests;
- Add a mDisappearing flag to prevent running disappear animation
  multiple times;
- Check whether activity is still active after disappear animation
  before setting result and finishing it;
- Remove no longer used mNumWrongConfirmAttempts;

Bug:23190499
Change-Id: If1784d3d1fcc152ac06137b12748b9def5726692
This commit is contained in:
Xiyuan Xia
2015-08-31 11:59:46 -07:00
parent fea2b30ac4
commit 00b17fa3c3
3 changed files with 179 additions and 66 deletions

View File

@@ -16,10 +16,8 @@
package com.android.settings;
import android.os.UserHandle;
import android.text.TextUtils;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.TextViewInputDisabler;
@@ -78,19 +76,20 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
}
public static class ConfirmLockPasswordFragment extends ConfirmDeviceCredentialBaseFragment
implements OnClickListener, OnEditorActionListener {
private static final String KEY_NUM_WRONG_CONFIRM_ATTEMPTS
= "confirm_lock_password_fragment.key_num_wrong_confirm_attempts";
implements OnClickListener, OnEditorActionListener,
CredentialCheckResultTracker.Listener {
private static final long ERROR_MESSAGE_TIMEOUT = 3000;
private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
private TextView mPasswordEntry;
private TextViewInputDisabler mPasswordEntryInputDisabler;
private LockPatternUtils mLockPatternUtils;
private AsyncTask<?, ?, ?> mPendingLockCheck;
private CredentialCheckResultTracker mCredentialCheckResultTracker;
private boolean mDisappearing = false;
private TextView mHeaderTextView;
private TextView mDetailsTextView;
private TextView mErrorTextView;
private Handler mHandler = new Handler();
private int mNumWrongConfirmAttempts;
private CountDownTimer mCountdownTimer;
private boolean mIsAlpha;
private InputMethodManager mImm;
@@ -110,11 +109,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
super.onCreate(savedInstanceState);
mLockPatternUtils = new LockPatternUtils(getActivity());
mEffectiveUserId = Utils.getEffectiveUserId(getActivity());
if (savedInstanceState != null) {
mNumWrongConfirmAttempts = savedInstanceState.getInt(
KEY_NUM_WRONG_CONFIRM_ATTEMPTS, 0);
}
}
@Override
@@ -165,6 +159,15 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
0.5f /* delayScale */, AnimationUtils.loadInterpolator(
getContext(), android.R.interpolator.fast_out_linear_in));
setAccessibilityTitle(mHeaderTextView.getText());
mCredentialCheckResultTracker = (CredentialCheckResultTracker) getFragmentManager()
.findFragmentByTag(FRAGMENT_TAG_CHECK_LOCK_RESULT);
if (mCredentialCheckResultTracker == null) {
mCredentialCheckResultTracker = new CredentialCheckResultTracker();
getFragmentManager().beginTransaction().add(mCredentialCheckResultTracker,
FRAGMENT_TAG_CHECK_LOCK_RESULT).commit();
}
return view;
}
@@ -227,10 +230,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
mCountdownTimer.cancel();
mCountdownTimer = null;
}
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
mPendingLockCheck = null;
}
mCredentialCheckResultTracker.setListener(null);
}
@Override
@@ -243,21 +243,17 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
super.onResume();
long deadline = mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId);
if (deadline != 0) {
mCredentialCheckResultTracker.clearResult();
handleAttemptLockout(deadline);
} else {
resetState();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(KEY_NUM_WRONG_CONFIRM_ATTEMPTS, mNumWrongConfirmAttempts);
mCredentialCheckResultTracker.setListener(this);
}
@Override
protected void authenticationSucceeded() {
startDisappearAnimation(new Intent());
mCredentialCheckResultTracker.setResult(true, new Intent(), 0, mEffectiveUserId);
}
@Override
@@ -298,11 +294,12 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
}
private void handleNext() {
mPasswordEntryInputDisabler.setInputEnabled(false);
if (mPendingLockCheck != null) {
mPendingLockCheck.cancel(false);
if (mPendingLockCheck != null || mDisappearing) {
return;
}
mPasswordEntryInputDisabler.setInputEnabled(false);
final String pin = mPasswordEntry.getText().toString();
final boolean verifyChallenge = getActivity().getIntent().getBooleanExtra(
ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
@@ -317,7 +314,7 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
return;
}
onPasswordChecked(false, intent, 0, mEffectiveUserId);
mCredentialCheckResultTracker.setResult(false, intent, 0, mEffectiveUserId);
}
private boolean isInternalActivity() {
@@ -344,7 +341,8 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
token);
}
onPasswordChecked(matched, intent, timeoutMs, localEffectiveUserId);
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
}
});
}
@@ -366,16 +364,27 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
intent.putExtra(
ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, pin);
}
onPasswordChecked(matched, intent, timeoutMs, localEffectiveUserId);
mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
localEffectiveUserId);
}
});
}
private void startDisappearAnimation(final Intent intent) {
if (mDisappearing) {
return;
}
mDisappearing = true;
if (getActivity().getThemeResId() == R.style.Theme_ConfirmDeviceCredentialsDark) {
mDisappearAnimationUtils.startAnimation(getActiveViews(), new Runnable() {
@Override
public void run() {
// Bail if there is no active activity.
if (getActivity() == null || getActivity().isFinishing()) {
return;
}
getActivity().setResult(RESULT_OK, intent);
getActivity().finish();
getActivity().overridePendingTransition(
@@ -405,6 +414,12 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
}
}
@Override
public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
int effectiveUserId) {
onPasswordChecked(matched, intent, timeoutMs, effectiveUserId);
}
private void handleAttemptLockout(long elapsedRealtimeDeadline) {
long elapsedRealtime = SystemClock.elapsedRealtime();
mPasswordEntry.setEnabled(false);
@@ -424,7 +439,6 @@ public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
public void onFinish() {
resetState();
mErrorTextView.setText("");
mNumWrongConfirmAttempts = 0;
}
}.start();
}