summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl1
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java15
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java35
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java14
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java23
5 files changed, 88 insertions, 0 deletions
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 82367834f93d..511c6802677e 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -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);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index e46b8d7c5fae..f4ad487f48ac 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -449,6 +449,21 @@ public class LockPatternUtils {
}
/**
+ * 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.
*
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index b90480a1e794..92a7d8ef890d 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -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
@@ -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());
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 71576465e035..7aae91b98348 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -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
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
index 70150c507460..4396c679ec24 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
@@ -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;
@@ -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);