Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Do not dismiss keyguard after SIM PUK unlock
Browse files Browse the repository at this point in the history
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.

Fixes: 238804980
Bug: 218500036
Test: atest KeyguardSecurityContainerTest
AdminSecondaryLockScreenControllerTest KeyguardHostViewControllerTest
KeyguardSecurityContainerControllerTest

Change-Id: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
Merged-In: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
(cherry picked from commit 37aeb26)
(cherry picked from commit 3d89cc5)
Merged-In: I7c8714a177bc85fbce92f6e8fe911f74ca2ac243
  • Loading branch information
mpietal79 authored and Android Build Coastguard Worker committed Sep 19, 2022
1 parent 71bbded commit ecbed81
Show file tree
Hide file tree
Showing 12 changed files with 102 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import android.view.ViewGroup;

import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.keyguard.dagger.KeyguardBouncerScope;
import com.android.systemui.dagger.qualifiers.Main;

Expand Down Expand Up @@ -208,7 +209,7 @@ private void dismiss(int userId) {
hide();
if (mKeyguardCallback != null) {
mKeyguardCallback.dismiss(/* securityVerified= */ true, userId,
/* bypassSecondaryLockScreen= */true);
/* bypassSecondaryLockScreen= */true, SecurityMode.Invalid);

This comment has been minimized.

Copy link
@rebtail

rebtail Dec 4, 2022

Nice

}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ void onPasswordChecked(int userId, boolean matched, int timeoutMs, boolean isVal
if (dismissKeyguard) {
mDismissing = true;
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
getKeyguardSecurityCallback().dismiss(true, userId);
getKeyguardSecurityCallback().dismiss(true, userId, getSecurityMode());
}
} else {
if (isValidPassword) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void onTrustGrantedWithFlags(int flags, int userId) {
Log.i(TAG, "TrustAgent dismissed Keyguard.");
}
mSecurityCallback.dismiss(false /* authenticated */, userId,
/* bypassSecondaryLockScreen */ false);
/* bypassSecondaryLockScreen */ false, SecurityMode.Invalid);
} else {
mViewMediatorCallback.playTrustedSound();
}
Expand All @@ -102,9 +102,9 @@ public void onTrustGrantedWithFlags(int flags, int userId) {

@Override
public boolean dismiss(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
return mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
authenticated, targetUserId, bypassSecondaryLockScreen);
authenticated, targetUserId, bypassSecondaryLockScreen, expectedSecurityMode);
}

@Override
Expand Down Expand Up @@ -212,7 +212,8 @@ public void resetSecurityContainer() {
* @return True if the keyguard is done.
*/
public boolean dismiss(int targetUserId) {
return mSecurityCallback.dismiss(false, targetUserId, false);
return mSecurityCallback.dismiss(false, targetUserId, false,
getCurrentSecurityMode());
}

/**
Expand Down Expand Up @@ -355,10 +356,10 @@ public int getTop() {
}

public boolean handleBackKey() {
if (mKeyguardSecurityContainerController.getCurrentSecurityMode()
!= SecurityMode.None) {
SecurityMode securityMode = mKeyguardSecurityContainerController.getCurrentSecurityMode();
if (securityMode != SecurityMode.None) {
mKeyguardSecurityContainerController.dismiss(
false, KeyguardUpdateMonitor.getCurrentUser());
false, KeyguardUpdateMonitor.getCurrentUser(), securityMode);
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ public boolean isVerifyUnlockOnly() {
return false;
}
@Override
public void dismiss(boolean securityVerified, int targetUserId) { }
public void dismiss(boolean securityVerified, int targetUserId,
SecurityMode expectedSecurityMode) { }
@Override
public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) { }
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) { }
@Override
public void onUserInput() { }
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private void onPatternChecked(int userId, boolean matched, int timeoutMs,
if (dismissKeyguard) {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Correct);
mLatencyTracker.onActionStart(LatencyTracker.ACTION_LOCKSCREEN_UNLOCK);
getKeyguardSecurityCallback().dismiss(true, userId);
getKeyguardSecurityCallback().dismiss(true, userId, SecurityMode.Pattern);
}
} else {
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,28 @@
*/
package com.android.keyguard;

import com.android.keyguard.KeyguardSecurityModel.SecurityMode;

public interface KeyguardSecurityCallback {

/**
* Dismiss the given security 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 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.
* @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 bypassSecondaryLockScreen true if the user can bypass the secondary lock screen,
* 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,12 @@ private void updateChildren(int translationY, float alpha) {

// Used to notify the container when something interesting happens.
public interface SecurityCallback {
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen);
/**
* Potentially dismiss the current security screen, after validating that all device
* security has been unlocked. Otherwise show the next screen.
*/
boolean dismiss(boolean authenticated, int targetUserId, boolean bypassSecondaryLockScreen,
SecurityMode expectedSecurityMode);

void userActivity();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,17 @@ public void onUserInput() {
}

@Override
public void dismiss(boolean authenticated, int targetId) {
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false);
public void dismiss(boolean authenticated, int targetId,
SecurityMode expectedSecurityMode) {
dismiss(authenticated, targetId, /* bypassSecondaryLockScreen */ false,
expectedSecurityMode);
}

@Override
public void dismiss(boolean authenticated, int targetId,
boolean bypassSecondaryLockScreen) {
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen);
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {
mSecurityCallback.dismiss(authenticated, targetId, bypassSecondaryLockScreen,
expectedSecurityMode);
}

public boolean isVerifyUnlockOnly() {
Expand Down Expand Up @@ -350,8 +353,13 @@ public SecurityMode getCurrentSecurityMode() {
return mCurrentSecurityMode;
}

public void dismiss(boolean authenticated, int targetUserId) {
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId);
/**
* Potentially dismiss the current security screen, after validating that all device
* security has been unlocked. Otherwise show the next screen.
*/
public void dismiss(boolean authenticated, int targetUserId,
SecurityMode expectedSecurityMode) {
mKeyguardSecurityCallback.dismiss(authenticated, targetUserId, expectedSecurityMode);
}

public void reset() {
Expand Down Expand Up @@ -410,12 +418,21 @@ public void onStartingToHide() {
* completion.
* @param bypassSecondaryLockScreen true if the user is allowed to bypass the secondary
* 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
*/
public boolean showNextSecurityScreenOrFinish(boolean authenticated, int targetUserId,
boolean bypassSecondaryLockScreen) {
boolean bypassSecondaryLockScreen, SecurityMode expectedSecurityMode) {

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 strongAuth = false;
int eventSubtype = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ void onSimCheckResponse(final PinResult result) {
mRemainingAttempts = -1;
mShowDefaultMessage = true;
getKeyguardSecurityCallback().dismiss(
true, KeyguardUpdateMonitor.getCurrentUser());
true, KeyguardUpdateMonitor.getCurrentUser(),
SecurityMode.SimPin);
} else {
mShowDefaultMessage = false;
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ public void onSimStateChanged(int subId, int slotId, int simState) {
if (simState == TelephonyManager.SIM_STATE_READY) {
mRemainingAttempts = -1;
mShowDefaultMessage = true;
getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
getKeyguardSecurityCallback().dismiss(true, KeyguardUpdateMonitor.getCurrentUser(),
SecurityMode.SimPuk);
} else {
resetState();
}
Expand Down Expand Up @@ -278,7 +279,8 @@ void onSimLockChangedResponse(final PinResult result) {
mShowDefaultMessage = true;

getKeyguardSecurityCallback().dismiss(
true, KeyguardUpdateMonitor.getCurrentUser());
true, KeyguardUpdateMonitor.getCurrentUser(),
SecurityMode.SimPuk);
} else {
mShowDefaultMessage = false;
if (result.getResult() == PinResult.PIN_RESULT_TYPE_INCORRECT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

import androidx.test.filters.SmallTest;

import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
import com.android.systemui.SysuiTestCase;

import org.junit.After;
Expand Down Expand Up @@ -190,7 +191,7 @@ private SurfaceView verifySurfaceReady() throws Exception {

private void verifyViewDismissed(SurfaceView v) throws Exception {
verify(mKeyguardSecurityContainer).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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
import static com.android.keyguard.KeyguardSecurityContainer.MODE_DEFAULT;
import static com.android.keyguard.KeyguardSecurityContainer.MODE_ONE_HANDED;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -69,6 +72,7 @@
@TestableLooper.RunWithLooper()
public class KeyguardSecurityContainerControllerTest extends SysuiTestCase {
private static final int VIEW_WIDTH = 1600;
private static final int TARGET_USER_ID = 100;

@Rule
public MockitoRule mRule = MockitoJUnit.rule();
Expand Down Expand Up @@ -299,4 +303,42 @@ public void addUserSwitchCallback() {
verify(mUserSwitcherController)
.removeUserSwitchCallback(any(UserSwitcherController.UserSwitchCallback.class));
}

@Test
public void showNextSecurityScreenOrFinish_setsSecurityScreenToPinAfterSimPinUnlock() {
// GIVEN the current security method is SimPin
when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
when(mKeyguardUpdateMonitor.getUserUnlockedWithBiometric(TARGET_USER_ID)).thenReturn(false);
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.SimPin);

// WHEN a request is made from the SimPin screens to show the next security method
when(mKeyguardSecurityModel.getSecurityMode(TARGET_USER_ID)).thenReturn(SecurityMode.PIN);
mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
/* authenticated= */true,
TARGET_USER_ID,
/* bypassSecondaryLockScreen= */true,
SecurityMode.SimPin);

// THEN the next security method of PIN is set, and the keyguard is not marked as done
verify(mSecurityCallback, never()).finish(anyBoolean(), anyInt());
assertThat(mKeyguardSecurityContainerController.getCurrentSecurityMode())
.isEqualTo(SecurityMode.PIN);
}

@Test
public void showNextSecurityScreenOrFinish_ignoresCallWhenSecurityMethodHasChanged() {
//GIVEN current security mode has been set to PIN
mKeyguardSecurityContainerController.showSecurityScreen(SecurityMode.PIN);

//WHEN a request comes from SimPin to dismiss the security screens
boolean keyguardDone = mKeyguardSecurityContainerController.showNextSecurityScreenOrFinish(
/* authenticated= */true,
TARGET_USER_ID,
/* bypassSecondaryLockScreen= */true,
SecurityMode.SimPin);

//THEN no action has happened, which will not dismiss the security screens
assertThat(keyguardDone).isEqualTo(false);
verify(mKeyguardUpdateMonitor, never()).getUserHasTrust(anyInt());
}
}

0 comments on commit ecbed81

Please sign in to comment.