[DO NOT MERGE] Do not dismiss keyguard after SIM PUK unlock

After PUK unlock, multiple calls to
KeyguardSecurityContainerController#dismiss() were being called from
the KeyguardSimPukViewController, which begins the transition to the
next security screen, if any. At the same time, other parts of the
system, also listening to SIM events, recognize the PUK unlock and
call KeyguardSecurityContainer#showSecurityScreen, which updates which
security method comes next. After boot, this should be one of PIN,
Password, Pattern, assuming they have a security method. If one of the
first dismiss() calls comes AFTER the security method changes, this is
incorrectly recognized by the code as a successful
PIN/pattern/password unlock. This causes the keyguard to be marked as
done, causing screen flickers and incorrect system state.

The solution: every call to dismiss() should include a new parameter
for the security method used. If there is a difference between this
parameter and the current value in KeyguardSecurityContainerCallback,
ignore the request, as the system state has changed.

Bug: 218500036
Test: atest KeyguardSecurityContainerTest

Merged-In: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
Change-Id: I30226bc7b5eda9480d471b35fe81e106b0491ff8
This commit is contained in:
Matt Pietal
2022-08-18 12:04:43 +00:00
parent f8f07e22f1
commit c27cf661a6
11 changed files with 76 additions and 25 deletions

View File

@@ -33,6 +33,7 @@ import android.view.SurfaceView;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@@ -204,7 +205,7 @@ public class AdminSecondaryLockScreenController {
hide(); hide();
if (mKeyguardCallback != null) { if (mKeyguardCallback != null) {
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId, mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
/* bypassSecondaryLockScreen= */true); /* bypassSecondaryLockScreen= */true, SecurityMode.Invalid);
} }
} }
} }

View File

@@ -30,6 +30,7 @@ import android.view.KeyEvent;
import android.view.View; import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.internal.util.LatencyTracker; import com.android.internal.util.LatencyTracker;
import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
@@ -99,6 +100,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
protected abstract int getPasswordTextViewId(); protected abstract int getPasswordTextViewId();
protected abstract void resetState(); protected abstract void resetState();
protected abstract SecurityMode getSecurityMode();
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
@@ -208,7 +210,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout
mCallback.reportUnlockAttempt(userId, true, 0); mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) { if (dismissKeyguard) {
mDismissing = true; mDismissing = true;
mCallback.dismiss(true, userId); mCallback.dismiss(true, userId, getSecurityMode());
} }
} else { } else {
if (isValidPassword) { if (isValidPassword) {

View File

@@ -87,7 +87,7 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
Log.i(TAG, "TrustAgent dismissed Keyguard."); Log.i(TAG, "TrustAgent dismissed Keyguard.");
} }
dismiss(false /* authenticated */, userId, dismiss(false /* authenticated */, userId,
/* bypassSecondaryLockScreen */ false); /* bypassSecondaryLockScreen */ false, SecurityMode.Invalid);
} else { } else {
mViewMediatorCallback.playTrustedSound(); mViewMediatorCallback.playTrustedSound();
} }
@@ -193,12 +193,13 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
* @return True if the keyguard is done. * @return True if the keyguard is done.
*/ */
public boolean dismiss(int targetUserId) { public boolean dismiss(int targetUserId) {
return dismiss(false, targetUserId, false); return dismiss(false, targetUserId, false, getCurrentSecurityMode());
} }
public boolean handleBackKey() { public boolean handleBackKey() {
if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) { if (mSecurityContainer.getCurrentSecuritySelection() != SecurityMode.None) {
mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser()); mSecurityContainer.dismiss(false, KeyguardUpdateMonitor.getCurrentUser(),
getCurrentSecurityMode());
return true; return true;
} }
return false; return false;
@@ -210,9 +211,9 @@ public class KeyguardHostView extends FrameLayout implements SecurityCallback {
@Override @Override
public boolean dismiss(boolean authenticated, int targetUserId, public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) { boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId, return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated, targetUserId,
bypassSecondaryLockScreen); bypassSecondaryLockScreen, expectedSecurityMode);
} }
/** /**

View File

@@ -22,6 +22,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils;
import com.android.systemui.Dependency; import com.android.systemui.Dependency;
@@ -183,4 +184,9 @@ public class KeyguardPINView extends KeyguardPinBasedInputView {
public boolean hasOverlappingRendering() { public boolean hasOverlappingRendering() {
return false; return false;
} }
@Override
public SecurityMode getSecurityMode() {
return SecurityMode.PIN;
}
} }

View File

@@ -38,6 +38,7 @@ import android.widget.TextView.OnEditorActionListener;
import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.TextViewInputDisabler; import com.android.internal.widget.TextViewInputDisabler;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.R; import com.android.systemui.R;
import java.util.List; import java.util.List;
@@ -387,4 +388,9 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView
return getContext().getString( return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_password_unlock); com.android.internal.R.string.keyguard_accessibility_password_unlock);
} }
@Override
public SecurityMode getSecurityMode() {
return SecurityMode.Password;
}
} }

View File

@@ -40,6 +40,7 @@ import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView; import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.LockscreenCredential;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.settingslib.animation.AppearAnimationCreator; import com.android.settingslib.animation.AppearAnimationCreator;
import com.android.settingslib.animation.AppearAnimationUtils; import com.android.settingslib.animation.AppearAnimationUtils;
import com.android.settingslib.animation.DisappearAnimationUtils; import com.android.settingslib.animation.DisappearAnimationUtils;
@@ -352,7 +353,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
mCallback.reportUnlockAttempt(userId, true, 0); mCallback.reportUnlockAttempt(userId, true, 0);
if (dismissKeyguard) { if (dismissKeyguard) {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct); mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
mCallback.dismiss(true, userId); mCallback.dismiss(true, userId, SecurityMode.Pattern);
} }
} else { } else {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong); mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);

View File

@@ -15,14 +15,17 @@
*/ */
package com.android.keyguard; package com.android.keyguard;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
public interface KeyguardSecurityCallback { public interface KeyguardSecurityCallback {
/** /**
* Dismiss the given security screen. * Dismiss the given security screen.
* @param securityVerified true if the user correctly entered credentials for the given screen. * @param securityVerified true if the user correctly entered credentials for the given screen.
* @param targetUserId a user that needs to be the foreground user at the dismissal completion. * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param expectedSecurityMode The security mode that is invoking this dismiss.
*/ */
void dismiss(boolean securityVerified, int targetUserId); void dismiss(boolean securityVerified, int targetUserId, SecurityMode expectedSecurityMode);
/** /**
* Dismiss the given security screen. * Dismiss the given security screen.
@@ -30,8 +33,10 @@ public interface KeyguardSecurityCallback {
* @param targetUserId a user that needs to be the foreground user at the dismissal completion. * @param targetUserId a user that needs to be the foreground user at the dismissal completion.
* @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen, * @param bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
* if any, during this dismissal. * if any, during this dismissal.
* @param expectedSecurityMode The security mode that is invoking this dismiss.
*/ */
void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen); void dismiss(boolean securityVerified, int targetUserId, boolean bypassSecondaryLockScreen,
SecurityMode expectedSecurityMode);
/** /**
* Manually report user activity to keep the device awake. * Manually report user activity to keep the device awake.

View File

@@ -189,7 +189,7 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
// Used to notify the container when something interesting happens. // Used to notify the container when something interesting happens.
public interface SecurityCallback { public interface SecurityCallback {
public boolean dismiss(boolean authenticated, int targetUserId, public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen); boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode);
public void userActivity(); public void userActivity();
public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput); public void onSecurityModeChanged(SecurityMode securityMode, boolean needsInput);
@@ -676,11 +676,20 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
* completion. * completion.
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary * @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
* secondary lock screen requirement, if any. * secondary lock screen requirement, if any.
* @param expectedSecurityMode SecurityMode that is invoking this request. SecurityMode.Invalid
* indicates that no check should be done
* @return true if keyguard is done * @return true if keyguard is done
*/ */
boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId, boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) { boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")"); if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
if (expectedSecurityMode != SecurityMode.Invalid
&& expectedSecurityMode != getCurrentSecurityMode()) {
Log.w(TAG, "Attempted to invoke showNextSecurityScreenOrFinish with securityMode "
+ expectedSecurityMode + ", but current mode is " + getCurrentSecurityMode());
return false;
}
boolean finish = false; boolean finish = false;
boolean strongAuth = false; boolean strongAuth = false;
int eventSubtype = -1; int eventSubtype = -1;
@@ -819,14 +828,17 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
} }
@Override @Override
public void dismiss(boolean authenticated, int targetId) { public void dismiss(boolean authenticated, int targetId,
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false); SecurityMode expectedSecurityMode) {
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false,
expectedSecurityMode);
} }
@Override @Override
public void dismiss(boolean authenticated, int targetId, public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) { boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen); mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
expectedSecurityMode);
} }
public boolean isVerifyUnlockOnly() { public boolean isVerifyUnlockOnly() {
@@ -878,10 +890,11 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
@Override @Override
public boolean isVerifyUnlockOnly() { return false; } public boolean isVerifyUnlockOnly() { return false; }
@Override @Override
public void dismiss(boolean securityVerified, int targetUserId) { } public void dismiss(boolean securityVerified, int targetUserId,
SecurityMode expectedSecurityMode) { }
@Override @Override
public void dismiss(boolean authenticated, int targetId, public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) { } boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
@Override @Override
public void onUserInput() { } public void onUserInput() { }
@Override @Override
@@ -933,8 +946,9 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
return mCurrentSecuritySelection; return mCurrentSecuritySelection;
} }
public void dismiss(boolean authenticated, int targetUserId) { public void dismiss(boolean authenticated, int targetUserId,
mCallback.dismiss(authenticated, targetUserId); SecurityMode expectedSecurityMode) {
mCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
} }
public boolean needsInput() { public boolean needsInput() {

View File

@@ -37,6 +37,7 @@ import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.ImageView; import android.widget.ImageView;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Dependency; import com.android.systemui.Dependency;
import com.android.systemui.R; import com.android.systemui.R;
@@ -348,7 +349,8 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
mRemainingAttempts = -1; mRemainingAttempts = -1;
mShowDefaultMessage = true; mShowDefaultMessage = true;
if (mCallback != null) { if (mCallback != null) {
mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
SecurityMode.SimPin);
} }
} else { } else {
mShowDefaultMessage = false; mShowDefaultMessage = false;
@@ -398,5 +400,10 @@ public class KeyguardSimPinView extends KeyguardPinBasedInputView {
return getContext().getString( return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock); com.android.internal.R.string.keyguard_accessibility_sim_pin_unlock);
} }
@Override
public SecurityMode getSecurityMode() {
return SecurityMode.SimPin;
}
} }

View File

@@ -36,6 +36,7 @@ import android.view.View;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.ImageView; import android.widget.ImageView;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.Dependency; import com.android.systemui.Dependency;
import com.android.systemui.R; import com.android.systemui.R;
@@ -76,7 +77,8 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
// mCallback can be null if onSimStateChanged callback is called when keyguard // mCallback can be null if onSimStateChanged callback is called when keyguard
// isn't active. // isn't active.
if (mCallback != null) { if (mCallback != null) {
mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser()); mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
SecurityMode.SimPuk);
} }
break; break;
} }
@@ -422,8 +424,8 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
mRemainingAttempts = -1; mRemainingAttempts = -1;
mShowDefaultMessage = true; mShowDefaultMessage = true;
if (mCallback != null) { if (mCallback != null) {
mCallback.dismiss(true, mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
KeyguardUpdateMonitor.getCurrentUser()); SecurityMode.SimPuk);
} }
} else { } else {
mShowDefaultMessage = false; mShowDefaultMessage = false;
@@ -479,6 +481,11 @@ public class KeyguardSimPukView extends KeyguardPinBasedInputView {
return getContext().getString( return getContext().getString(
com.android.internal.R.string.keyguard_accessibility_sim_puk_unlock); com.android.internal.R.string.keyguard_accessibility_sim_puk_unlock);
} }
@Override
public SecurityMode getSecurityMode() {
return SecurityMode.SimPuk;
}
} }

View File

@@ -46,6 +46,7 @@ import android.widget.FrameLayout;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import org.junit.After; import org.junit.After;
@@ -191,7 +192,7 @@ public class AdminSecondaryLockScreenControllerTest extends SysuiTestCase {
private void verifyViewDismissed(SurfaceView v) throws Exception { private void verifyViewDismissed(SurfaceView v) throws Exception {
verify(mParent).removeView(v); verify(mParent).removeView(v);
verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true); verify(mKeyguardCallback).dismiss(true, TARGET_USER_ID, true, SecurityMode.Invalid);
assertThat(mContext.isBound(mComponentName)).isFalse(); assertThat(mContext.isBound(mComponentName)).isFalse();
} }
} }