Loading core/java/com/android/internal/widget/ILockSettings.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -109,4 +109,5 @@ interface ILockSettings { boolean isWeakEscrowTokenActive(long handle, int userId); boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId); void unlockUserKeyIfUnsecured(int userId); boolean writeRepairModeCredential(int userId); } core/java/com/android/internal/widget/LockPatternUtils.java +15 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ public class LockPatternUtils { null /* componentName */, userId); } /** * Save the current password data to the repair mode file. * * @return true if success or false otherwise. */ public boolean writeRepairModeCredential(int userId) { throwIfCalledOnMainThread(); try { return getLockSettings().writeRepairModeCredential(userId); } catch (RemoteException re) { Log.e(TAG, "Failed to write repair mode credential", re); return false; } } /** * Check to see if a credential matches the saved one. * If credential matches, return an opaque attestation that the challenge was verified. Loading core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import org.mockito.ArgumentCaptor; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.CompletableFuture; @RunWith(AndroidJUnit4.class) @SmallTest Loading Loading @@ -316,6 +317,40 @@ public class LockPatternUtilsTest { assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE); } @Test public void testWriteRepairModeCredential_mainThread() { createTestLockSettings(); var context = InstrumentationRegistry.getTargetContext(); var future = new CompletableFuture<Exception>(); context.getMainThreadHandler().post(() -> { try { mLockPatternUtils.writeRepairModeCredential(USER_ID); future.complete(null); } catch (Exception e) { future.complete(e); } }); var e = future.join(); assertThat(e).isNotNull(); assertThat(e.getMessage()).contains("should not be called from the main thread"); } @Test public void testWriteRepairModeCredential() throws Exception { var ils = createTestLockSettings(); when(ils.writeRepairModeCredential(USER_ID)).thenReturn(false); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); when(ils.writeRepairModeCredential(USER_ID)).thenReturn(true); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isTrue(); when(ils.writeRepairModeCredential(USER_ID)).thenThrow(new RemoteException()); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); } private TestStrongAuthTracker createStrongAuthTracker() { final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()); return new TestStrongAuthTracker(context, Looper.getMainLooper()); Loading services/core/java/com/android/server/locksettings/LockSettingsService.java +14 −0 Original line number Diff line number Diff line Loading @@ -1773,6 +1773,20 @@ public class LockSettingsService extends ILockSettings.Stub { } } @Override public boolean writeRepairModeCredential(int userId) { checkWritePermission(); final long identity = Binder.clearCallingIdentity(); try { synchronized (mSpManager) { long protectorId = getCurrentLskfBasedProtectorId(userId); return mSpManager.writeRepairModeCredentialLocked(protectorId, userId); } } finally { Binder.restoreCallingIdentity(identity); } } /** * @param savedCredential if the user is a profile with * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and Loading services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.locksettings; import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE; import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; Loading Loading @@ -199,6 +201,27 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests { .getResponseCode()); } @Test public void writeRepairModeCredential_noLock() { assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isFalse(); } @Test public void writeRepairModeCredential_hasLock() { mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isTrue(); } @Test public void writeRepairModeCredential_verifyRepairModeUser() { mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); mService.writeRepairModeCredential(PRIMARY_USER_ID); setRepairModeActive(true); var response = mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0); assertThat(response.isMatched()).isTrue(); } private void setRepairModeActive(boolean active) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0); Loading Loading
core/java/com/android/internal/widget/ILockSettings.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -109,4 +109,5 @@ interface ILockSettings { boolean isWeakEscrowTokenActive(long handle, int userId); boolean isWeakEscrowTokenValid(long handle, in byte[] token, int userId); void unlockUserKeyIfUnsecured(int userId); boolean writeRepairModeCredential(int userId); }
core/java/com/android/internal/widget/LockPatternUtils.java +15 −0 Original line number Diff line number Diff line Loading @@ -448,6 +448,21 @@ public class LockPatternUtils { null /* componentName */, userId); } /** * Save the current password data to the repair mode file. * * @return true if success or false otherwise. */ public boolean writeRepairModeCredential(int userId) { throwIfCalledOnMainThread(); try { return getLockSettings().writeRepairModeCredential(userId); } catch (RemoteException re) { Log.e(TAG, "Failed to write repair mode credential", re); return false; } } /** * Check to see if a credential matches the saved one. * If credential matches, return an opaque attestation that the challenge was verified. Loading
core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java +35 −0 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import org.mockito.ArgumentCaptor; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.CompletableFuture; @RunWith(AndroidJUnit4.class) @SmallTest Loading Loading @@ -316,6 +317,40 @@ public class LockPatternUtilsTest { assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE); } @Test public void testWriteRepairModeCredential_mainThread() { createTestLockSettings(); var context = InstrumentationRegistry.getTargetContext(); var future = new CompletableFuture<Exception>(); context.getMainThreadHandler().post(() -> { try { mLockPatternUtils.writeRepairModeCredential(USER_ID); future.complete(null); } catch (Exception e) { future.complete(e); } }); var e = future.join(); assertThat(e).isNotNull(); assertThat(e.getMessage()).contains("should not be called from the main thread"); } @Test public void testWriteRepairModeCredential() throws Exception { var ils = createTestLockSettings(); when(ils.writeRepairModeCredential(USER_ID)).thenReturn(false); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); when(ils.writeRepairModeCredential(USER_ID)).thenReturn(true); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isTrue(); when(ils.writeRepairModeCredential(USER_ID)).thenThrow(new RemoteException()); assertThat(mLockPatternUtils.writeRepairModeCredential(USER_ID)).isFalse(); } private TestStrongAuthTracker createStrongAuthTracker() { final Context context = new ContextWrapper(InstrumentationRegistry.getTargetContext()); return new TestStrongAuthTracker(context, Looper.getMainLooper()); Loading
services/core/java/com/android/server/locksettings/LockSettingsService.java +14 −0 Original line number Diff line number Diff line Loading @@ -1773,6 +1773,20 @@ public class LockSettingsService extends ILockSettings.Stub { } } @Override public boolean writeRepairModeCredential(int userId) { checkWritePermission(); final long identity = Binder.clearCallingIdentity(); try { synchronized (mSpManager) { long protectorId = getCurrentLskfBasedProtectorId(userId); return mSpManager.writeRepairModeCredentialLocked(protectorId, userId); } } finally { Binder.restoreCallingIdentity(identity); } } /** * @param savedCredential if the user is a profile with * {@link UserManager#isCredentialSharableWithParent()} with unified challenge and Loading
services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java +23 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.server.locksettings; import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE; import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; Loading Loading @@ -199,6 +201,27 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests { .getResponseCode()); } @Test public void writeRepairModeCredential_noLock() { assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isFalse(); } @Test public void writeRepairModeCredential_hasLock() { mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); assertThat(mService.writeRepairModeCredential(PRIMARY_USER_ID)).isTrue(); } @Test public void writeRepairModeCredential_verifyRepairModeUser() { mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID); mService.writeRepairModeCredential(PRIMARY_USER_ID); setRepairModeActive(true); var response = mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0); assertThat(response.isMatched()).isTrue(); } private void setRepairModeActive(boolean active) { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0); Loading