Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26426cee authored by Eric Biggers's avatar Eric Biggers Committed by Android (Google) Code Review
Browse files

Merge "Keep track of whether LockscreenCredential is a unified profile password" into main

parents 8a9e11f9 a1d399d8
Loading
Loading
Loading
Loading
+64 −24
Original line number Diff line number Diff line
@@ -78,6 +78,10 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
    // needed to do that check, since the conversion to mCredential may have been lossy.
    private final boolean mHasInvalidChars;

    // Whether the credential is a unified profile password, i.e. a long random password the system
    // generates and manages transparently to the user. Implies mType == CREDENTIAL_TYPE_PASSWORD.
    private final boolean mIsUnifiedProfilePassword;

    /**
     * Private constructor, use static builder methods instead.
     *
@@ -85,7 +89,11 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
     * array and pass it in here. LockscreenCredential will only store the reference internally
     * without copying. This is to minimize the number of extra copies introduced.
     */
    private LockscreenCredential(int type, byte[] credential, boolean hasInvalidChars) {
    private LockscreenCredential(
            int type,
            byte[] credential,
            boolean hasInvalidChars,
            boolean isUnifiedProfilePassword) {
        Objects.requireNonNull(credential);
        if (type == CREDENTIAL_TYPE_NONE) {
            Preconditions.checkArgument(credential.length == 0);
@@ -102,28 +110,37 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
            // LockscreenCredential object to be constructed so that the validation logic can run,
            // even though the validation logic will ultimately reject the credential as too short.
        }
        Preconditions.checkState(!isUnifiedProfilePassword || type == CREDENTIAL_TYPE_PASSWORD);
        mType = type;
        mCredential = credential;
        mHasInvalidChars = hasInvalidChars;
        mIsUnifiedProfilePassword = isUnifiedProfilePassword;
    }

    private LockscreenCredential(int type, CharSequence credential) {
        this(type, charsToBytesTruncating(credential), hasInvalidChars(credential));
        this(
                type,
                charsToBytesTruncating(credential),
                hasInvalidChars(credential),
                /* isUnifiedProfilePassword= */ false);
    }

    /**
     * Creates a LockscreenCredential object representing a none credential.
     */
    public static LockscreenCredential createNone() {
        return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0], false);
        return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0], false, false);
    }

    /**
     * Creates a LockscreenCredential object representing the given pattern.
     */
    public static LockscreenCredential createPattern(@NonNull List<LockPatternView.Cell> pattern) {
        return new LockscreenCredential(CREDENTIAL_TYPE_PATTERN,
                LockPatternUtils.patternToByteArray(pattern), /* hasInvalidChars= */ false);
        return new LockscreenCredential(
                CREDENTIAL_TYPE_PATTERN,
                LockPatternUtils.patternToByteArray(pattern),
                /* hasInvalidChars= */ false,
                /* isUnifiedProfilePassword= */ false);
    }

    /**
@@ -140,8 +157,11 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
     * can then supersede the isLockTiedToParent argument in various places in LSS.
     */
    public static LockscreenCredential createUnifiedProfilePassword(@NonNull byte[] password) {
        return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
                copyOfArrayNonMovable(password), /* hasInvalidChars= */ false);
        return new LockscreenCredential(
                CREDENTIAL_TYPE_PASSWORD,
                copyOfArrayNonMovable(password),
                /* hasInvalidChars= */ false,
                /* isUnifiedProfilePassword= */ true);
    }

    /**
@@ -234,11 +254,24 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
        return mHasInvalidChars;
    }

    /**
     * Returns whether this is a unified profile password credential.
     *
     * <p>Note that currently "unified profile password" is not a dedicated credential type, but
     * rather a subset of the "password" type. {@link #isPassword()} also returns true for them.
     */
    public boolean isUnifiedProfilePassword() {
        ensureNotZeroized();
        return mIsUnifiedProfilePassword;
    }

    /** Create a copy of the credential */
    public LockscreenCredential duplicate() {
        return new LockscreenCredential(mType,
        return new LockscreenCredential(
                mType,
                mCredential != null ? copyOfArrayNonMovable(mCredential) : null,
                mHasInvalidChars);
                mHasInvalidChars,
                mIsUnifiedProfilePassword);
    }

    /**
@@ -367,6 +400,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
        dest.writeInt(mType);
        dest.writeByteArray(mCredential);
        dest.writeBoolean(mHasInvalidChars);
        dest.writeBoolean(mIsUnifiedProfilePassword);
    }

    public static final Parcelable.Creator<LockscreenCredential> CREATOR =
@@ -374,7 +408,10 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {

                @Override
                public LockscreenCredential createFromParcel(Parcel source) {
            return new LockscreenCredential(source.readInt(), source.createByteArray(),
                    return new LockscreenCredential(
                            source.readInt(),
                            source.createByteArray(),
                            source.readBoolean(),
                            source.readBoolean());
                }

@@ -402,7 +439,8 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
    @Override
    public int hashCode() {
        // Effective Java — Always override hashCode when you override equals
        return Objects.hash(mType, Arrays.hashCode(mCredential), mHasInvalidChars);
        return Objects.hash(
                mType, Arrays.hashCode(mCredential), mHasInvalidChars, mIsUnifiedProfilePassword);
    }

    @Override
@@ -410,8 +448,10 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
        if (o == this) return true;
        if (!(o instanceof LockscreenCredential)) return false;
        final LockscreenCredential other = (LockscreenCredential) o;
        return mType == other.mType && Arrays.equals(mCredential, other.mCredential)
            && mHasInvalidChars == other.mHasInvalidChars;
        return mType == other.mType
                && Arrays.equals(mCredential, other.mCredential)
                && mHasInvalidChars == other.mHasInvalidChars
                && mIsUnifiedProfilePassword == other.mIsUnifiedProfilePassword;
    }

    private static boolean hasInvalidChars(CharSequence chars) {
+40 −0
Original line number Diff line number Diff line
@@ -31,7 +31,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.Arrays;
import java.util.Random;

/** atest FrameworksCoreTests:LockscreenCredentialTest */
@RunWith(AndroidJUnit4.class)
public class LockscreenCredentialTest {

@@ -46,6 +48,7 @@ public class LockscreenCredentialTest {
        assertFalse(none.isPin());
        assertFalse(none.isPassword());
        assertFalse(none.isPattern());
        assertFalse(none.isUnifiedProfilePassword());
        assertFalse(none.hasInvalidChars());
        none.validateBasicRequirements();
    }
@@ -61,6 +64,7 @@ public class LockscreenCredentialTest {
        assertFalse(pin.isNone());
        assertFalse(pin.isPassword());
        assertFalse(pin.isPattern());
        assertFalse(pin.isUnifiedProfilePassword());
        assertFalse(pin.hasInvalidChars());
        pin.validateBasicRequirements();
    }
@@ -76,6 +80,7 @@ public class LockscreenCredentialTest {
        assertFalse(password.isNone());
        assertFalse(password.isPin());
        assertFalse(password.isPattern());
        assertFalse(password.isUnifiedProfilePassword());
        assertFalse(password.hasInvalidChars());
        password.validateBasicRequirements();
    }
@@ -97,10 +102,30 @@ public class LockscreenCredentialTest {
        assertFalse(pattern.isNone());
        assertFalse(pattern.isPin());
        assertFalse(pattern.isPassword());
        assertFalse(pattern.isUnifiedProfilePassword());
        assertFalse(pattern.hasInvalidChars());
        pattern.validateBasicRequirements();
    }

    @Test
    public void testUnifiedProfilePasswordCredential() {
        final byte[] passwordBytes = new byte[40];
        new Random().nextBytes(passwordBytes);
        final LockscreenCredential password =
                LockscreenCredential.createUnifiedProfilePassword(passwordBytes);

        assertTrue(password.isPassword());
        assertTrue(password.isUnifiedProfilePassword());
        assertEquals(passwordBytes.length, password.size());
        assertArrayEquals(passwordBytes, password.getCredential());

        assertFalse(password.isNone());
        assertFalse(password.isPin());
        assertFalse(password.isPattern());
        assertFalse(password.hasInvalidChars());
        password.validateBasicRequirements();
    }

    // Constructing a LockscreenCredential with a too-short length, even 0, should not throw an
    // exception.  This is because LockscreenCredential needs to be able to represent a request to
    // set a credential that is too short.
@@ -196,6 +221,11 @@ public class LockscreenCredentialTest {
            password.hasInvalidChars();
            fail("Sanitized credential still accessible");
        } catch (IllegalStateException expected) { }
        try {
            password.isUnifiedProfilePassword();
            fail("Sanitized credential still accessible");
        } catch (IllegalStateException expected) {
        }
        try {
            password.getCredential();
            fail("Sanitized credential still accessible");
@@ -242,6 +272,12 @@ public class LockscreenCredentialTest {
        // the same byte[] (due to the truncation bug) but different values of mHasInvalidChars.
        assertNotEquals(LockscreenCredential.createPassword("™™™™"),
                LockscreenCredential.createPassword("\"\"\"\""));

        // Test that mIsUnifiedProfilePassword is compared.
        final String password = "password";
        assertNotEquals(
                LockscreenCredential.createPassword(password),
                LockscreenCredential.createUnifiedProfilePassword(password.getBytes()));
    }

    @Test
@@ -260,6 +296,10 @@ public class LockscreenCredentialTest {
        // Test that mHasInvalidChars is duplicated.
        credential = LockscreenCredential.createPassword("™™™™");
        assertEquals(credential, credential.duplicate());

        // Test that mIsUnifiedProfilePassword is duplicated.
        credential = LockscreenCredential.createUnifiedProfilePassword("password".getBytes());
        assertEquals(credential, credential.duplicate());
    }

    @Test