Merge "Fix broken docs in media" into main
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 1812c2b..fd4e3df 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6634,12 +6634,6 @@
android.security.attestationverification.AttestationVerificationManager
android.security.keymaster.ExportResult$1
android.security.keymaster.ExportResult
-android.security.keymaster.IKeyAttestationApplicationIdProvider$Stub
-android.security.keymaster.IKeyAttestationApplicationIdProvider
-android.security.keymaster.KeyAttestationApplicationId$1
-android.security.keymaster.KeyAttestationApplicationId
-android.security.keymaster.KeyAttestationPackageInfo$1
-android.security.keymaster.KeyAttestationPackageInfo
android.security.keymaster.KeyCharacteristics$1
android.security.keymaster.KeyCharacteristics
android.security.keymaster.KeymasterArgument$1
@@ -6664,7 +6658,13 @@
android.security.keystore.BackendBusyException
android.security.keystore.DelegatingX509Certificate
android.security.keystore.DeviceIdAttestationException
+android.security.keystore.IKeyAttestationApplicationIdProvider$Stub
+android.security.keystore.IKeyAttestationApplicationIdProvider
+android.security.keystore.KeyAttestationApplicationId$Stub
+android.security.keystore.KeyAttestationApplicationId
android.security.keystore.KeyAttestationException
+android.security.keystore.KeyAttestationPackageInfo$Stub
+android.security.keystore.KeyAttestationPackageInfo
android.security.keystore.KeyExpiredException
android.security.keystore.KeyGenParameterSpec$Builder
android.security.keystore.KeyGenParameterSpec
@@ -6687,6 +6687,8 @@
android.security.keystore.KeystoreResponse
android.security.keystore.ParcelableKeyGenParameterSpec$1
android.security.keystore.ParcelableKeyGenParameterSpec
+android.security.keystore.Signature$Stub
+android.security.keystore.Signature
android.security.keystore.SecureKeyImportUnavailableException
android.security.keystore.StrongBoxUnavailableException
android.security.keystore.UserAuthArgs
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5091b52..70864d5 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -23,11 +23,6 @@
visibility: ["//frameworks/base"],
}
-filegroup {
- name: "IKeyAttestationApplicationIdProvider.aidl",
- srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"],
-}
-
aidl_library {
name: "IDropBoxManagerService_aidl",
srcs: [
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 7ed3a1d..6a51171 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -60,6 +60,7 @@
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockscreenCredential;
+import com.android.internal.widget.PasswordValidationError;
import com.android.internal.widget.VerifyCredentialResponse;
import java.nio.charset.Charset;
@@ -916,17 +917,14 @@
if (!checkInitialLockMethodUsage()) {
return false;
}
+ Objects.requireNonNull(password, "Password cannot be null.");
complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
- // TODO: b/131755827 add devicePolicyManager support for Auto
- DevicePolicyManager devicePolicyManager =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
PasswordMetrics adminMetrics =
- devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
- // Check if the password fits the mold of a pin or pattern.
- boolean isPinOrPattern = lockType != PASSWORD;
-
- return PasswordMetrics.validatePassword(
- adminMetrics, complexity, isPinOrPattern, password).size() == 0;
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
+ try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
+ return PasswordMetrics.validateCredential(adminMetrics, complexity,
+ credential).size() == 0;
+ }
}
/**
@@ -945,11 +943,8 @@
return -1;
}
complexity = PasswordMetrics.sanitizeComplexityLevel(complexity);
- // TODO: b/131755827 add devicePolicyManager support for Auto
- DevicePolicyManager devicePolicyManager =
- (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
PasswordMetrics adminMetrics =
- devicePolicyManager.getPasswordMinimumMetrics(mContext.getUserId());
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
PasswordMetrics minMetrics =
PasswordMetrics.applyComplexity(adminMetrics, isPin, complexity);
return minMetrics.length;
@@ -1171,6 +1166,14 @@
currentLockType, currentPassword);
LockscreenCredential newCredential = createLockscreenCredential(
newLockType, newPassword);
+ PasswordMetrics adminMetrics =
+ mLockPatternUtils.getRequestedPasswordMetrics(mContext.getUserId());
+ List<PasswordValidationError> errors = PasswordMetrics.validateCredential(adminMetrics,
+ DevicePolicyManager.PASSWORD_COMPLEXITY_NONE, newCredential);
+ if (!errors.isEmpty()) {
+ Log.e(TAG, "New credential is not valid: " + errors.get(0));
+ return false;
+ }
return mLockPatternUtils.setLockCredential(newCredential, currentCredential, userId);
}
diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java
index ab48791..dd31175 100644
--- a/core/java/android/app/admin/PasswordMetrics.java
+++ b/core/java/android/app/admin/PasswordMetrics.java
@@ -30,6 +30,7 @@
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PASSWORD_SIZE;
+import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PATTERN_SIZE;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS;
import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE;
import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS;
@@ -134,17 +135,6 @@
}
}
- private static boolean hasInvalidCharacters(byte[] password) {
- // Allow non-control Latin-1 characters only.
- for (byte b : password) {
- char c = (char) b;
- if (c < 32 || c > 127) {
- return true;
- }
- }
- return false;
- }
-
@Override
public int describeContents() {
return 0;
@@ -189,19 +179,15 @@
};
/**
- * Returns the {@code PasswordMetrics} for a given credential.
- *
- * If the credential is a pin or a password, equivalent to
- * {@link #computeForPasswordOrPin(byte[], boolean)}. {@code credential} cannot be null
- * when {@code type} is
- * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}.
+ * Returns the {@code PasswordMetrics} for the given credential.
*/
public static PasswordMetrics computeForCredential(LockscreenCredential credential) {
if (credential.isPassword() || credential.isPin()) {
- return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(),
- credential.isPin());
+ return computeForPasswordOrPin(credential.getCredential(), credential.isPin());
} else if (credential.isPattern()) {
- return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+ PasswordMetrics metrics = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN);
+ metrics.length = credential.size();
+ return metrics;
} else if (credential.isNone()) {
return new PasswordMetrics(CREDENTIAL_TYPE_NONE);
} else {
@@ -210,10 +196,10 @@
}
/**
- * Returns the {@code PasswordMetrics} for a given password or pin
+ * Returns the {@code PasswordMetrics} for the given password or pin.
*/
- public static PasswordMetrics computeForPasswordOrPin(byte[] password, boolean isPin) {
- // Analyse the characters used
+ private static PasswordMetrics computeForPasswordOrPin(byte[] credential, boolean isPin) {
+ // Analyze the characters used.
int letters = 0;
int upperCase = 0;
int lowerCase = 0;
@@ -221,8 +207,8 @@
int symbols = 0;
int nonLetter = 0;
int nonNumeric = 0;
- final int length = password.length;
- for (byte b : password) {
+ final int length = credential.length;
+ for (byte b : credential) {
switch (categoryChar((char) b)) {
case CHAR_LOWER_CASE:
letters++;
@@ -247,7 +233,7 @@
}
final int credType = isPin ? CREDENTIAL_TYPE_PIN : CREDENTIAL_TYPE_PASSWORD;
- final int seqLength = maxLengthSequence(password);
+ final int seqLength = maxLengthSequence(credential);
return new PasswordMetrics(credType, length, letters, upperCase, lowerCase,
numeric, symbols, nonLetter, nonNumeric, seqLength);
}
@@ -513,26 +499,24 @@
}
/**
- * Validates password against minimum metrics and complexity.
+ * Validates a proposed lockscreen credential against minimum metrics and complexity.
*
- * @param adminMetrics - minimum metrics to satisfy admin requirements.
- * @param minComplexity - minimum complexity imposed by the requester.
- * @param isPin - whether it is PIN that should be only digits
- * @param password - password to validate.
- * @return a list of password validation errors. An empty list means the password is OK.
+ * @param adminMetrics minimum metrics to satisfy admin requirements
+ * @param minComplexity minimum complexity imposed by the requester
+ * @param credential the proposed lockscreen credential
+ *
+ * @return a list of validation errors. An empty list means the credential is OK.
*
* TODO: move to PasswordPolicy
*/
- public static List<PasswordValidationError> validatePassword(
- PasswordMetrics adminMetrics, int minComplexity, boolean isPin, byte[] password) {
-
- if (hasInvalidCharacters(password)) {
+ public static List<PasswordValidationError> validateCredential(
+ PasswordMetrics adminMetrics, int minComplexity, LockscreenCredential credential) {
+ if (credential.hasInvalidChars()) {
return Collections.singletonList(
new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0));
}
-
- final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin);
- return validatePasswordMetrics(adminMetrics, minComplexity, enteredMetrics);
+ PasswordMetrics actualMetrics = computeForCredential(credential);
+ return validatePasswordMetrics(adminMetrics, minComplexity, actualMetrics);
}
/**
@@ -555,9 +539,18 @@
|| !bucket.allowsCredType(actualMetrics.credType)) {
return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0));
}
- if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD
- && actualMetrics.credType != CREDENTIAL_TYPE_PIN) {
- return Collections.emptyList(); // Nothing to check for pattern or none.
+ if (actualMetrics.credType == CREDENTIAL_TYPE_PATTERN) {
+ // For pattern, only need to check the length against the hardcoded minimum. If the
+ // pattern length is unavailable (e.g., PasswordMetrics that was stored on-disk before
+ // the pattern length started being included in it), assume it is okay.
+ if (actualMetrics.length != 0 && actualMetrics.length < MIN_LOCK_PATTERN_SIZE) {
+ return Collections.singletonList(new PasswordValidationError(TOO_SHORT,
+ MIN_LOCK_PATTERN_SIZE));
+ }
+ return Collections.emptyList();
+ }
+ if (actualMetrics.credType == CREDENTIAL_TYPE_NONE) {
+ return Collections.emptyList(); // Nothing to check for none.
}
if (actualMetrics.credType == CREDENTIAL_TYPE_PIN && actualMetrics.nonNumeric > 0) {
diff --git a/core/java/android/content/pm/Signature.aidl b/core/java/android/content/pm/Signature.aidl
deleted file mode 100644
index 36c127a..0000000
--- a/core/java/android/content/pm/Signature.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/* //device/java/android/android/view/WindowManager.aidl
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-package android.content.pm;
-
-/* For the key attestation application id provider service we needed a native implementation
- * of the Signature parcelable because the service is used by the native keystore.
- * The native implementation is now located at
- * system/security/keystore/Signature.cpp
- * and
- * system/security/keystore/include/keystore/Signature.h.
- * and can be used by linking against libkeystore_binder.
- *
- * This is not the best arrangement. If you, dear reader, happen to implement native implementations
- * for the package manager's parcelables, consider moving Signature.cpp/.h to your library and
- * adjust keystore's dependencies accordingly. Thank you.
- */
-parcelable Signature cpp_header "keystore/Signature.h";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index baeb1aa..9cdb9ce 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10442,20 +10442,6 @@
"assist_long_press_home_enabled";
/**
- * Control whether Trust Agents are in active unlock or extend unlock mode.
- * @hide
- */
- @Readable
- public static final String TRUST_AGENTS_EXTEND_UNLOCK = "trust_agents_extend_unlock";
-
- /**
- * Control whether the screen locks when trust is lost.
- * @hide
- */
- @Readable
- public static final String LOCK_SCREEN_WHEN_TRUST_LOST = "lock_screen_when_trust_lost";
-
- /**
* Control whether Night display is currently activated.
* @hide
*/
diff --git a/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl b/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
deleted file mode 100644
index dbffd5f..0000000
--- a/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-import android.security.keymaster.KeyAttestationApplicationId;
-import android.security.keymaster.KeyAttestationPackageInfo;
-import android.content.pm.Signature;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeyAttestationApplicationIdProvider {
- /* keep in sync with /system/security/keystore/keystore_attestation_id.cpp */
- KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
-}
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl b/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
deleted file mode 100644
index 9f6ff58..0000000
--- a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationApplicationId cpp_header "keystore/KeyAttestationApplicationId.h";
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.java b/core/java/android/security/keymaster/KeyAttestationApplicationId.java
deleted file mode 100644
index 670f30e1b..0000000
--- a/core/java/android/security/keymaster/KeyAttestationApplicationId.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * @hide
- * The information aggregated by this class is used by keystore to identify a caller of the
- * keystore API toward a remote party. It aggregates multiple PackageInfos because keystore
- * can only determine a caller by uid granularity, and a uid can be shared by multiple packages.
- * The remote party must decide if it trusts all of the packages enough to consider the
- * confidentiality of the key material in question intact.
- */
-public class KeyAttestationApplicationId implements Parcelable {
- private final KeyAttestationPackageInfo[] mAttestationPackageInfos;
-
- /**
- * @param mAttestationPackageInfos
- */
- public KeyAttestationApplicationId(KeyAttestationPackageInfo[] mAttestationPackageInfos) {
- super();
- this.mAttestationPackageInfos = mAttestationPackageInfos;
- }
-
- /**
- * @return the mAttestationPackageInfos
- */
- public KeyAttestationPackageInfo[] getAttestationPackageInfos() {
- return mAttestationPackageInfos;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeTypedArray(mAttestationPackageInfos, flags);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<KeyAttestationApplicationId> CREATOR
- = new Parcelable.Creator<KeyAttestationApplicationId>() {
- @Override
- public KeyAttestationApplicationId createFromParcel(Parcel source) {
- return new KeyAttestationApplicationId(source);
- }
-
- @Override
- public KeyAttestationApplicationId[] newArray(int size) {
- return new KeyAttestationApplicationId[size];
- }
- };
-
- KeyAttestationApplicationId(Parcel source) {
- mAttestationPackageInfos = source.createTypedArray(KeyAttestationPackageInfo.CREATOR);
- }
-}
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
deleted file mode 100644
index f8b843b..0000000
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
- */
-parcelable KeyAttestationPackageInfo cpp_header "keystore/KeyAttestationPackageInfo.h";
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
deleted file mode 100644
index c0b8d8d..0000000
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keymaster;
-
-import android.content.pm.Signature;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * @hide
- * This class constitutes and excerpt from the PackageManager's PackageInfo for the purpose of
- * key attestation. It is part of the KeyAttestationApplicationId, which is used by
- * keystore to identify the caller of the keystore API towards a remote party.
- */
-public class KeyAttestationPackageInfo implements Parcelable {
- private final String mPackageName;
- private final long mPackageVersionCode;
- private final Signature[] mPackageSignatures;
-
- /**
- * @param mPackageName
- * @param mPackageVersionCode
- * @param mPackageSignatures
- */
- public KeyAttestationPackageInfo(
- String mPackageName, long mPackageVersionCode, Signature[] mPackageSignatures) {
- super();
- this.mPackageName = mPackageName;
- this.mPackageVersionCode = mPackageVersionCode;
- this.mPackageSignatures = mPackageSignatures;
- }
- /**
- * @return the mPackageName
- */
- public String getPackageName() {
- return mPackageName;
- }
- /**
- * @return the mPackageVersionCode
- */
- public long getPackageVersionCode() {
- return mPackageVersionCode;
- }
- /**
- * @return the mPackageSignatures
- */
- public Signature[] getPackageSignatures() {
- return mPackageSignatures;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mPackageName);
- dest.writeLong(mPackageVersionCode);
- dest.writeTypedArray(mPackageSignatures, flags);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<KeyAttestationPackageInfo> CREATOR
- = new Parcelable.Creator<KeyAttestationPackageInfo>() {
- @Override
- public KeyAttestationPackageInfo createFromParcel(Parcel source) {
- return new KeyAttestationPackageInfo(source);
- }
-
- @Override
- public KeyAttestationPackageInfo[] newArray(int size) {
- return new KeyAttestationPackageInfo[size];
- }
- };
-
- private KeyAttestationPackageInfo(Parcel source) {
- mPackageName = source.readString();
- mPackageVersionCode = source.readLong();
- mPackageSignatures = source.createTypedArray(Signature.CREATOR);
- }
-}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 0d0bfe3..d702963 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2536,7 +2536,7 @@
final int childrenCount = mChildrenCount;
if (childrenCount != 0) {
final float x = event.getXDispatchLocation(0);
- final float y = event.getXDispatchLocation(0);
+ final float y = event.getYDispatchLocation(0);
final ArrayList<View> preorderedList = buildOrderedChildList();
final boolean customOrder = preorderedList == null
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 490ec35..dc28fa4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -96,7 +96,7 @@
public static final int MIN_LOCK_PATTERN_SIZE = 4;
/**
- * The minimum size of a valid password.
+ * The minimum size of a valid password or PIN.
*/
public static final int MIN_LOCK_PASSWORD_SIZE = 4;
@@ -771,7 +771,6 @@
* and return false if the given credential is wrong.
* @throws RuntimeException if password change encountered an unrecoverable error.
* @throws UnsupportedOperationException secure lockscreen is not supported on this device.
- * @throws IllegalArgumentException if new credential is too short.
*/
public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
@@ -779,7 +778,6 @@
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
- newCredential.checkLength();
try {
if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
@@ -1543,7 +1541,6 @@
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
- credential.checkLength();
LockSettingsInternal localService = getLockSettingsInternal();
return localService.setLockCredentialWithToken(credential, tokenHandle, token, userHandle);
diff --git a/core/java/com/android/internal/widget/LockscreenCredential.java b/core/java/com/android/internal/widget/LockscreenCredential.java
index 03e7fd1..c88763c 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -60,10 +60,24 @@
public class LockscreenCredential implements Parcelable, AutoCloseable {
private final int mType;
- // Stores raw credential bytes, or null if credential has been zeroized. An empty password
+ // Stores raw credential bytes, or null if credential has been zeroized. A none credential
// is represented as a byte array of length 0.
private byte[] mCredential;
+ // This indicates that the credential used characters outside ASCII 32–127.
+ //
+ // Such credentials were never intended to be allowed. However, Android 10–14 had a bug where
+ // conversion from the chars the user entered to the credential bytes used a simple truncation.
+ // Thus, any 'char' whose remainder mod 256 was in the range 32–127 was accepted and was
+ // equivalent to some ASCII character. For example, ™, which is U+2122, was truncated to ASCII
+ // 0x22 which is the double-quote character ".
+ //
+ // We have to continue to allow a LockscreenCredential to be constructed with this bug, so that
+ // existing devices can be unlocked if their password used this bug. However, we prevent new
+ // passwords that use this bug from being set. The boolean below keeps track of the information
+ // needed to do that check, since the conversion to mCredential may have been lossy.
+ private final boolean mHasInvalidChars;
+
/**
* Private constructor, use static builder methods instead.
*
@@ -71,7 +85,7 @@
* 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) {
+ private LockscreenCredential(int type, byte[] credential, boolean hasInvalidChars) {
Objects.requireNonNull(credential);
if (type == CREDENTIAL_TYPE_NONE) {
Preconditions.checkArgument(credential.length == 0);
@@ -80,17 +94,28 @@
Preconditions.checkArgument(type == CREDENTIAL_TYPE_PIN
|| type == CREDENTIAL_TYPE_PASSWORD
|| type == CREDENTIAL_TYPE_PATTERN);
- Preconditions.checkArgument(credential.length > 0);
+ // Do not validate credential.length yet. All non-none credentials have a minimum
+ // length requirement; however, one of the uses of LockscreenCredential is to represent
+ // a proposed credential that might be too short. For example, a LockscreenCredential
+ // with type CREDENTIAL_TYPE_PIN and length 0 represents an attempt to set an empty PIN.
+ // This differs from an actual attempt to set a none credential. We have to allow the
+ // 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.
}
mType = type;
mCredential = credential;
+ mHasInvalidChars = hasInvalidChars;
+ }
+
+ private LockscreenCredential(int type, CharSequence credential) {
+ this(type, charsToBytesTruncating(credential), hasInvalidChars(credential));
}
/**
- * Creates a LockscreenCredential object representing empty password.
+ * Creates a LockscreenCredential object representing a none credential.
*/
public static LockscreenCredential createNone() {
- return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0]);
+ return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0], false);
}
/**
@@ -98,15 +123,14 @@
*/
public static LockscreenCredential createPattern(@NonNull List<LockPatternView.Cell> pattern) {
return new LockscreenCredential(CREDENTIAL_TYPE_PATTERN,
- LockPatternUtils.patternToByteArray(pattern));
+ LockPatternUtils.patternToByteArray(pattern), /* hasInvalidChars= */ false);
}
/**
* Creates a LockscreenCredential object representing the given alphabetic password.
*/
public static LockscreenCredential createPassword(@NonNull CharSequence password) {
- return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
- charSequenceToByteArray(password));
+ return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD, password);
}
/**
@@ -117,20 +141,19 @@
*/
public static LockscreenCredential createManagedPassword(@NonNull byte[] password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
- Arrays.copyOf(password, password.length));
+ Arrays.copyOf(password, password.length), /* hasInvalidChars= */ false);
}
/**
* Creates a LockscreenCredential object representing the given numeric PIN.
*/
public static LockscreenCredential createPin(@NonNull CharSequence pin) {
- return new LockscreenCredential(CREDENTIAL_TYPE_PIN,
- charSequenceToByteArray(pin));
+ return new LockscreenCredential(CREDENTIAL_TYPE_PIN, pin);
}
/**
* Creates a LockscreenCredential object representing the given alphabetic password.
- * If the supplied password is empty, create an empty credential object.
+ * If the supplied password is empty, create a none credential object.
*/
public static LockscreenCredential createPasswordOrNone(@Nullable CharSequence password) {
if (TextUtils.isEmpty(password)) {
@@ -142,7 +165,7 @@
/**
* Creates a LockscreenCredential object representing the given numeric PIN.
- * If the supplied password is empty, create an empty credential object.
+ * If the supplied password is empty, create a none credential object.
*/
public static LockscreenCredential createPinOrNone(@Nullable CharSequence pin) {
if (TextUtils.isEmpty(pin)) {
@@ -175,7 +198,7 @@
return mCredential;
}
- /** Returns whether this is an empty credential */
+ /** Returns whether this is a none credential */
public boolean isNone() {
ensureNotZeroized();
return mType == CREDENTIAL_TYPE_NONE;
@@ -205,10 +228,17 @@
return mCredential.length;
}
+ /** Returns true if this credential was constructed with any chars outside the allowed range */
+ public boolean hasInvalidChars() {
+ ensureNotZeroized();
+ return mHasInvalidChars;
+ }
+
/** Create a copy of the credential */
public LockscreenCredential duplicate() {
return new LockscreenCredential(mType,
- mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null);
+ mCredential != null ? Arrays.copyOf(mCredential, mCredential.length) : null,
+ mHasInvalidChars);
}
/**
@@ -222,27 +252,37 @@
}
/**
- * Check if the credential meets minimal length requirement.
+ * Checks whether the credential meets basic requirements for setting it as a new credential.
*
- * @throws IllegalArgumentException if the credential is too short.
+ * This is redundant if {@link android.app.admin.PasswordMetrics#validateCredential()}, which
+ * does more comprehensive checks, is correctly called first (which it should be).
+ *
+ * @throws IllegalArgumentException if the credential contains invalid characters or is too
+ * short
*/
- public void checkLength() {
- if (isNone()) {
- return;
+ public void validateBasicRequirements() {
+ if (mHasInvalidChars) {
+ throw new IllegalArgumentException("credential contains invalid characters");
}
- if (isPattern()) {
- if (size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
- throw new IllegalArgumentException("pattern must not be null and at least "
- + LockPatternUtils.MIN_LOCK_PATTERN_SIZE + " dots long.");
- }
- return;
- }
- if (isPassword() || isPin()) {
- if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) {
- throw new IllegalArgumentException("password must not be null and at least "
- + "of length " + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE);
- }
- return;
+ switch (getType()) {
+ case CREDENTIAL_TYPE_PATTERN:
+ if (size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
+ throw new IllegalArgumentException("pattern must be at least "
+ + LockPatternUtils.MIN_LOCK_PATTERN_SIZE + " dots long.");
+ }
+ break;
+ case CREDENTIAL_TYPE_PIN:
+ if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) {
+ throw new IllegalArgumentException("PIN must be at least "
+ + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE + " digits long.");
+ }
+ break;
+ case CREDENTIAL_TYPE_PASSWORD:
+ if (size() < LockPatternUtils.MIN_LOCK_PASSWORD_SIZE) {
+ throw new IllegalArgumentException("password must be at least "
+ + LockPatternUtils.MIN_LOCK_PASSWORD_SIZE + " characters long.");
+ }
+ break;
}
}
@@ -317,6 +357,7 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeByteArray(mCredential);
+ dest.writeBoolean(mHasInvalidChars);
}
public static final Parcelable.Creator<LockscreenCredential> CREATOR =
@@ -324,7 +365,8 @@
@Override
public LockscreenCredential createFromParcel(Parcel source) {
- return new LockscreenCredential(source.readInt(), source.createByteArray());
+ return new LockscreenCredential(source.readInt(), source.createByteArray(),
+ source.readBoolean());
}
@Override
@@ -346,7 +388,7 @@
@Override
public int hashCode() {
// Effective Java — Always override hashCode when you override equals
- return Objects.hash(mType, Arrays.hashCode(mCredential));
+ return Objects.hash(mType, Arrays.hashCode(mCredential), mHasInvalidChars);
}
@Override
@@ -354,20 +396,45 @@
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);
+ return mType == other.mType && Arrays.equals(mCredential, other.mCredential)
+ && mHasInvalidChars == other.mHasInvalidChars;
+ }
+
+ private static boolean hasInvalidChars(CharSequence chars) {
+ //
+ // Consider the password to have invalid characters if it contains any non-ASCII characters
+ // or control characters. There are multiple reasons for this restriction:
+ //
+ // - Non-ASCII characters might only be possible to enter on a third-party keyboard app
+ // (IME) that is available when setting the password but not when verifying it after a
+ // reboot. This can happen if the keyboard is not direct boot aware or gets uninstalled.
+ //
+ // - Unicode strings that look identical to the user can map to different byte[]. Yet, only
+ // one byte[] can be accepted. Unicode normalization can solve this problem to some
+ // extent, but still many Unicode characters look similar and could cause confusion.
+ //
+ // - For backwards compatibility reasons, the upper 8 bits of the 16-bit 'chars' are
+ // discarded by charsToBytesTruncating(). Thus, as-is passwords with characters above
+ // U+00FF (255) are not as secure as they should be. IMPORTANT: Do not change the below
+ // code to allow characters above U+00FF (255) without fixing this issue!
+ //
+ for (int i = 0; i < chars.length(); i++) {
+ char c = chars.charAt(i);
+ if (c < 32 || c > 127) {
+ return true;
+ }
+ }
+ return false;
}
/**
- * Converts a CharSequence to a byte array without requiring a toString(), which creates an
- * additional copy.
+ * Converts a CharSequence to a byte array, intentionally truncating chars greater than 255 for
+ * backwards compatibility reasons. See {@link #mHasInvalidChars}.
*
* @param chars The CharSequence to convert
* @return A byte array representing the input
*/
- private static byte[] charSequenceToByteArray(CharSequence chars) {
- if (chars == null) {
- return new byte[0];
- }
+ private static byte[] charsToBytesTruncating(CharSequence chars) {
byte[] bytes = new byte[chars.length()];
for (int i = 0; i < chars.length(); i++) {
bytes[i] = (byte) chars.charAt(i);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 55382cc..bfd80a9e 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -157,12 +157,8 @@
// ****************************************************************************
// ****************************************************************************
-static constexpr int32_t PROXY_WARN_INTERVAL = 5000;
static constexpr uint32_t GC_INTERVAL = 1000;
-static std::atomic<uint32_t> gNumProxies(0);
-static std::atomic<uint32_t> gProxiesWarned(0);
-
// Number of GlobalRefs held by JavaBBinders.
static std::atomic<uint32_t> gNumLocalRefsCreated(0);
static std::atomic<uint32_t> gNumLocalRefsDeleted(0);
@@ -842,19 +838,7 @@
return NULL;
}
BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
- if (actualNativeData == nativeData) {
- // Created a new Proxy
- uint32_t numProxies = gNumProxies.fetch_add(1, std::memory_order_relaxed);
- uint32_t numLastWarned = gProxiesWarned.load(std::memory_order_relaxed);
- if (numProxies >= numLastWarned + PROXY_WARN_INTERVAL) {
- // Multiple threads can get here, make sure only one of them gets to
- // update the warn counter.
- if (gProxiesWarned.compare_exchange_strong(numLastWarned,
- numLastWarned + PROXY_WARN_INTERVAL, std::memory_order_relaxed)) {
- ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
- }
- }
- } else {
+ if (actualNativeData != nativeData) {
delete nativeData;
}
@@ -1209,7 +1193,7 @@
jint android_os_Debug_getProxyObjectCount(JNIEnv* env, jobject clazz)
{
- return gNumProxies.load();
+ return BpBinder::getBinderProxyCount();
}
jint android_os_Debug_getDeathObjectCount(JNIEnv* env, jobject clazz)
@@ -1494,7 +1478,6 @@
nativeData->mObject.get(), nativeData->mOrgue.get());
delete nativeData;
IPCThreadState::self()->flushCommands();
- --gNumProxies;
}
JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) {
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 58f97b0..93048ea 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1022,7 +1022,7 @@
requires swapping ROTATION_90 and ROTATION_270.
TODO(b/265991392): This should eventually be configured and parsed in
display_settings.xml -->
- <bool name="config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay">true</bool>
+ <bool name="config_matchSecondaryInternalDisplaysOrientationToReverseDefaultDisplay">false</bool>
<!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
<integer-array name="config_availableColorModes">
diff --git a/core/tests/coretests/src/android/app/KeyguardManagerTest.java b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
index 958906c..ed8b288 100644
--- a/core/tests/coretests/src/android/app/KeyguardManagerTest.java
+++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
@@ -174,6 +174,22 @@
}
@Test
+ public void setLock_validatesCredential() {
+ // setLock() should validate the credential before setting it. Test one example, which is
+ // that PINs must contain only ASCII digits 0-9, i.e. bytes 48-57. Using bytes 0-9 is
+ // incorrect and should *not* be accepted.
+ byte[] invalidPin = new byte[] { 1, 2, 3, 4 };
+ byte[] validPin = "1234".getBytes();
+
+ assertFalse(mKeyguardManager.setLock(KeyguardManager.PIN, invalidPin, -1, null));
+ assertFalse(mKeyguardManager.isDeviceSecure());
+
+ assertTrue(mKeyguardManager.setLock(KeyguardManager.PIN, validPin, -1, null));
+ assertTrue(mKeyguardManager.isDeviceSecure());
+ assertTrue(mKeyguardManager.setLock(-1, null, KeyguardManager.PIN, validPin));
+ }
+
+ @Test
public void checkLock_correctCredentials() {
// Set to `true` to behave as if SET_INITIAL_LOCK permission had been granted.
doReturn(true).when(mKeyguardManager).checkInitialLockMethodUsage();
diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
index c9e02f8..33e81c1 100644
--- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
+++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java
@@ -25,6 +25,7 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static android.app.admin.PasswordMetrics.complexityLevelToMinQuality;
import static android.app.admin.PasswordMetrics.sanitizeComplexityLevel;
+import static android.app.admin.PasswordMetrics.validateCredential;
import static android.app.admin.PasswordMetrics.validatePasswordMetrics;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
@@ -41,6 +42,8 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;
import org.junit.Test;
@@ -94,8 +97,7 @@
@Test
public void testComputeForPassword_metrics() {
- final PasswordMetrics metrics = PasswordMetrics.computeForPasswordOrPin(
- "6B~0z1Z3*8A".getBytes(), /* isPin */ false);
+ final PasswordMetrics metrics = metricsForPassword("6B~0z1Z3*8A");
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
@@ -133,72 +135,54 @@
@Test
public void testDetermineComplexity_lowNumeric() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("1234".getBytes(),
- /* isPin */true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPin("1234").determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("124".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPin("124").determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("a!".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPassword("a!").determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_LOW,
- PasswordMetrics.computeForPasswordOrPin("a!1".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_LOW, metricsForPassword("a!1").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("1238".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPin("1238").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("ab!c".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPassword("ab!c").determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
- assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
- PasswordMetrics.computeForPasswordOrPin("ab!1".getBytes(),
- /* isPin */ false).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_MEDIUM, metricsForPassword("ab!1").determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
- assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("12389647!".getBytes(),
- /* isPin */ true).determineComplexity());
+ assertEquals(PASSWORD_COMPLEXITY_HIGH, metricsForPin("12389647!").determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("alphabetic!".getBytes(),
- /* isPin */ false).determineComplexity());
+ metricsForPassword("alphabetic!").determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
- PasswordMetrics.computeForPasswordOrPin("alphanumeric123!".getBytes(),
- /* isPin */ false).determineComplexity());
+ metricsForPassword("alphanumeric123!").determineComplexity());
}
@Test
@@ -374,8 +358,74 @@
PasswordValidationError.NOT_ENOUGH_NON_DIGITS, 1);
}
+ @Test
+ public void testValidateCredential_none() {
+ PasswordMetrics adminMetrics;
+ LockscreenCredential none = LockscreenCredential.createNone();
+
+ adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, none));
+
+ adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, none),
+ PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
+ }
+
+ @Test
+ public void testValidateCredential_password() {
+ PasswordMetrics adminMetrics;
+ LockscreenCredential password;
+
+ adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ password = LockscreenCredential.createPassword("password");
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_LOW, password));
+
+ // Test that validateCredential() checks LockscreenCredential#hasInvalidChars().
+ adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ password = LockscreenCredential.createPassword("™™™™");
+ assertTrue(password.hasInvalidChars());
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_LOW, password),
+ PasswordValidationError.CONTAINS_INVALID_CHARACTERS, 0);
+
+ // Test one more case where validateCredential() should reject the password. Beyond this,
+ // the unit tests for the lower-level method validatePasswordMetrics() should be sufficient.
+ adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ adminMetrics.length = 6;
+ password = LockscreenCredential.createPassword("pass");
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_LOW, password),
+ PasswordValidationError.TOO_SHORT, 6);
+ }
+
+ private LockscreenCredential createPattern(String patternString) {
+ return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
+ patternString.getBytes()));
+ }
+
+ private static PasswordMetrics metricsForPassword(String password) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPassword(password));
+ }
+
+ private static PasswordMetrics metricsForPin(String pin) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPin(pin));
+ }
+
+ @Test
+ public void testValidateCredential_pattern() {
+ PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("123")),
+ PasswordValidationError.TOO_SHORT, 4);
+ assertValidationErrors(
+ validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("1234")));
+ }
+
/**
- * @param expected sequense of validation error codes followed by requirement values, must have
+ * @param expected sequence of validation error codes followed by requirement values, must have
* even number of elements. Empty means no errors.
*/
private void assertValidationErrors(
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
index b37c8fd..bce3f3e 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -49,11 +49,11 @@
public void testDispatchMouseEventsUnderCursor() {
final Context context = getInstrumentation().getContext();
final TestView viewGroup = new TestView(context, 0 /* left */, 0 /* top */,
- 200 /* right */, 200 /* bottom */);
+ 200 /* right */, 100 /* bottom */);
final TestView viewA = spy(new TestView(context, 0 /* left */, 0 /* top */,
- 100 /* right */, 200 /* bottom */));
+ 100 /* right */, 100 /* bottom */));
final TestView viewB = spy(new TestView(context, 100 /* left */, 0 /* top */,
- 200 /* right */, 200 /* bottom */));
+ 200 /* right */, 100 /* bottom */));
viewGroup.addView(viewA);
viewGroup.addView(viewB);
@@ -73,10 +73,10 @@
MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[2];
coords[0] = new MotionEvent.PointerCoords();
coords[0].x = 80;
- coords[0].y = 100;
+ coords[0].y = 50;
coords[1] = new MotionEvent.PointerCoords();
coords[1].x = 240;
- coords[1].y = 100;
+ coords[1].y = 50;
MotionEvent event;
// Make sure the down event is active with a pointer which coordinate is different from the
@@ -91,6 +91,10 @@
viewGroup.onResolvePointerIcon(event, 0 /* pointerIndex */);
verify(viewB).onResolvePointerIcon(event, 0);
+ event.setAction(MotionEvent.ACTION_SCROLL);
+ viewGroup.dispatchGenericMotionEvent(event);
+ verify(viewB).dispatchGenericMotionEvent(event);
+
event = MotionEvent.obtain(0 /* downTime */, 0 /* eventTime */,
MotionEvent.ACTION_POINTER_DOWN | (1 << MotionEvent.ACTION_POINTER_INDEX_SHIFT),
2 /* pointerCount */, properties, coords, 0 /* metaState */, 0 /* buttonState */,
@@ -102,8 +106,13 @@
viewGroup.onResolvePointerIcon(event, 1 /* pointerIndex */);
verify(viewB).onResolvePointerIcon(event, 1);
+ event.setAction(MotionEvent.ACTION_SCROLL);
+ viewGroup.dispatchGenericMotionEvent(event);
+ verify(viewB).dispatchGenericMotionEvent(event);
+
verify(viewA, never()).dispatchTouchEvent(any());
verify(viewA, never()).onResolvePointerIcon(any(), anyInt());
+ verify(viewA, never()).dispatchGenericMotionEvent(any());
}
/**
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
index a47868d..5692742 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java
@@ -16,52 +16,71 @@
package com.android.internal.widget;
-
import static com.google.common.truth.Truth.assertThat;
-import android.test.AndroidTestCase;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Arrays;
+@RunWith(AndroidJUnit4.class)
+public class LockscreenCredentialTest {
-public class LockscreenCredentialTest extends AndroidTestCase {
+ @Test
+ public void testNoneCredential() {
+ LockscreenCredential none = LockscreenCredential.createNone();
- public void testEmptyCredential() {
- LockscreenCredential empty = LockscreenCredential.createNone();
+ assertTrue(none.isNone());
+ assertEquals(0, none.size());
+ assertArrayEquals(new byte[0], none.getCredential());
- assertTrue(empty.isNone());
- assertEquals(0, empty.size());
- assertNotNull(empty.getCredential());
-
- assertFalse(empty.isPin());
- assertFalse(empty.isPassword());
- assertFalse(empty.isPattern());
+ assertFalse(none.isPin());
+ assertFalse(none.isPassword());
+ assertFalse(none.isPattern());
+ assertFalse(none.hasInvalidChars());
+ none.validateBasicRequirements();
}
+ @Test
public void testPinCredential() {
LockscreenCredential pin = LockscreenCredential.createPin("3456");
assertTrue(pin.isPin());
assertEquals(4, pin.size());
- assertTrue(Arrays.equals("3456".getBytes(), pin.getCredential()));
+ assertArrayEquals("3456".getBytes(), pin.getCredential());
assertFalse(pin.isNone());
assertFalse(pin.isPassword());
assertFalse(pin.isPattern());
+ assertFalse(pin.hasInvalidChars());
+ pin.validateBasicRequirements();
}
+ @Test
public void testPasswordCredential() {
LockscreenCredential password = LockscreenCredential.createPassword("password");
assertTrue(password.isPassword());
assertEquals(8, password.size());
- assertTrue(Arrays.equals("password".getBytes(), password.getCredential()));
+ assertArrayEquals("password".getBytes(), password.getCredential());
assertFalse(password.isNone());
assertFalse(password.isPin());
assertFalse(password.isPattern());
+ assertFalse(password.hasInvalidChars());
+ password.validateBasicRequirements();
}
+ @Test
public void testPatternCredential() {
LockscreenCredential pattern = LockscreenCredential.createPattern(Arrays.asList(
LockPatternView.Cell.of(0, 0),
@@ -73,13 +92,34 @@
assertTrue(pattern.isPattern());
assertEquals(5, pattern.size());
- assertTrue(Arrays.equals("12369".getBytes(), pattern.getCredential()));
+ assertArrayEquals("12369".getBytes(), pattern.getCredential());
assertFalse(pattern.isNone());
assertFalse(pattern.isPin());
assertFalse(pattern.isPassword());
+ assertFalse(pattern.hasInvalidChars());
+ pattern.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.
+ @Test
+ public void testZeroLengthCredential() {
+ LockscreenCredential credential = LockscreenCredential.createPin("");
+ assertTrue(credential.isPin());
+ assertEquals(0, credential.size());
+
+ credential = createPattern("");
+ assertTrue(credential.isPattern());
+ assertEquals(0, credential.size());
+
+ credential = LockscreenCredential.createPassword("");
+ assertTrue(credential.isPassword());
+ assertEquals(0, credential.size());
+ }
+
+ @Test
public void testPasswordOrNoneCredential() {
assertEquals(LockscreenCredential.createNone(),
LockscreenCredential.createPasswordOrNone(null));
@@ -89,6 +129,7 @@
LockscreenCredential.createPasswordOrNone("abcd"));
}
+ @Test
public void testPinOrNoneCredential() {
assertEquals(LockscreenCredential.createNone(),
LockscreenCredential.createPinOrNone(null));
@@ -98,6 +139,35 @@
LockscreenCredential.createPinOrNone("1357"));
}
+ // Test that passwords containing invalid characters that were incorrectly allowed in
+ // Android 10–14 are still interpreted in the same way, but are not allowed for new passwords.
+ @Test
+ public void testPasswordWithInvalidChars() {
+ // ™ is U+2122, which was truncated to ASCII 0x22 which is double quote.
+ String[] passwords = new String[] { "foo™", "™™™™", "™foo" };
+ String[] equivalentAsciiPasswords = new String[] { "foo\"", "\"\"\"\"", "\"foo" };
+ for (int i = 0; i < passwords.length; i++) {
+ LockscreenCredential credential = LockscreenCredential.createPassword(passwords[i]);
+ assertTrue(credential.hasInvalidChars());
+ assertArrayEquals(equivalentAsciiPasswords[i].getBytes(), credential.getCredential());
+ try {
+ credential.validateBasicRequirements();
+ fail("should not be able to set password with invalid chars");
+ } catch (IllegalArgumentException expected) { }
+ }
+ }
+
+ @Test
+ public void testPinWithInvalidChars() {
+ LockscreenCredential pin = LockscreenCredential.createPin("\n\n\n\n");
+ assertTrue(pin.hasInvalidChars());
+ try {
+ pin.validateBasicRequirements();
+ fail("should not be able to set PIN with invalid chars");
+ } catch (IllegalArgumentException expected) { }
+ }
+
+ @Test
public void testSanitize() {
LockscreenCredential password = LockscreenCredential.createPassword("password");
password.zeroize();
@@ -123,11 +193,16 @@
fail("Sanitized credential still accessible");
} catch (IllegalStateException expected) { }
try {
+ password.hasInvalidChars();
+ fail("Sanitized credential still accessible");
+ } catch (IllegalStateException expected) { }
+ try {
password.getCredential();
fail("Sanitized credential still accessible");
} catch (IllegalStateException expected) { }
}
+ @Test
public void testEquals() {
assertEquals(LockscreenCredential.createNone(), LockscreenCredential.createNone());
assertEquals(LockscreenCredential.createPassword("1234"),
@@ -136,34 +211,40 @@
LockscreenCredential.createPin("4321"));
assertEquals(createPattern("1234"), createPattern("1234"));
- assertNotSame(LockscreenCredential.createPassword("1234"),
+ assertNotEquals(LockscreenCredential.createPassword("1234"),
LockscreenCredential.createNone());
- assertNotSame(LockscreenCredential.createPassword("1234"),
+ assertNotEquals(LockscreenCredential.createPassword("1234"),
LockscreenCredential.createPassword("4321"));
- assertNotSame(LockscreenCredential.createPassword("1234"),
+ assertNotEquals(LockscreenCredential.createPassword("1234"),
createPattern("1234"));
- assertNotSame(LockscreenCredential.createPassword("1234"),
+ assertNotEquals(LockscreenCredential.createPassword("1234"),
LockscreenCredential.createPin("1234"));
- assertNotSame(LockscreenCredential.createPin("1111"),
+ assertNotEquals(LockscreenCredential.createPin("1111"),
LockscreenCredential.createNone());
- assertNotSame(LockscreenCredential.createPin("1111"),
+ assertNotEquals(LockscreenCredential.createPin("1111"),
LockscreenCredential.createPin("2222"));
- assertNotSame(LockscreenCredential.createPin("1111"),
+ assertNotEquals(LockscreenCredential.createPin("1111"),
createPattern("1111"));
- assertNotSame(LockscreenCredential.createPin("1111"),
+ assertNotEquals(LockscreenCredential.createPin("1111"),
LockscreenCredential.createPassword("1111"));
- assertNotSame(createPattern("5678"),
+ assertNotEquals(createPattern("5678"),
LockscreenCredential.createNone());
- assertNotSame(createPattern("5678"),
+ assertNotEquals(createPattern("5678"),
createPattern("1234"));
- assertNotSame(createPattern("5678"),
+ assertNotEquals(createPattern("5678"),
LockscreenCredential.createPassword("5678"));
- assertNotSame(createPattern("5678"),
+ assertNotEquals(createPattern("5678"),
LockscreenCredential.createPin("5678"));
+
+ // Test that mHasInvalidChars is compared. To do this, compare two passwords that map to
+ // the same byte[] (due to the truncation bug) but different values of mHasInvalidChars.
+ assertNotEquals(LockscreenCredential.createPassword("™™™™"),
+ LockscreenCredential.createPassword("\"\"\"\""));
}
+ @Test
public void testDuplicate() {
LockscreenCredential credential;
@@ -175,8 +256,13 @@
assertEquals(credential, credential.duplicate());
credential = createPattern("5678");
assertEquals(credential, credential.duplicate());
+
+ // Test that mHasInvalidChars is duplicated.
+ credential = LockscreenCredential.createPassword("™™™™");
+ assertEquals(credential, credential.duplicate());
}
+ @Test
public void testPasswordToHistoryHash() {
String password = "1234";
LockscreenCredential credential = LockscreenCredential.createPassword(password);
@@ -193,6 +279,7 @@
.isEqualTo(expectedHash);
}
+ @Test
public void testPasswordToHistoryHashInvalidInput() {
String password = "1234";
LockscreenCredential credential = LockscreenCredential.createPassword(password);
@@ -221,6 +308,7 @@
.isNull();
}
+ @Test
public void testLegacyPasswordToHash() {
String password = "1234";
String salt = "6d5331dd120077a0";
@@ -233,6 +321,7 @@
.isEqualTo(expectedHash);
}
+ @Test
public void testLegacyPasswordToHashInvalidInput() {
String password = "1234";
String salt = "6d5331dd120077a0";
diff --git a/keystore/aaid/aidl/Android.bp b/keystore/aaid/aidl/Android.bp
new file mode 100644
index 0000000..97acfb4
--- /dev/null
+++ b/keystore/aaid/aidl/Android.bp
@@ -0,0 +1,31 @@
+// Copyright 2020, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.security.aaid_aidl",
+ srcs: ["android/security/keystore/*.aidl"],
+ unstable: true,
+ backend: {
+ rust: {
+ enabled: true,
+ },
+ cpp: {
+ enabled: true,
+ },
+ },
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
new file mode 100644
index 0000000..c360cb8
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.security.keystore.KeyAttestationApplicationId;
+
+/** @hide */
+interface IKeyAttestationApplicationIdProvider {
+ /**
+ * Provides information describing the possible applications identified by a UID.
+ * @hide
+ */
+ KeyAttestationApplicationId getKeyAttestationApplicationId(int uid);
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl b/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl
new file mode 100644
index 0000000..c33e830
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.security.keystore.KeyAttestationPackageInfo;
+
+/**
+ * @hide
+ * The information aggregated by this parcelable is used by keystore to identify a caller of the
+ * keystore API toward a remote party. It aggregates multiple PackageInfos because keystore
+ * can only determine a caller by uid granularity, and a uid can be shared by multiple packages.
+ * The remote party must decide if it trusts all of the packages enough to consider the
+ * confidentiality of the key material in question intact.
+ */
+parcelable KeyAttestationApplicationId {
+ KeyAttestationPackageInfo[] packageInfos;
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
new file mode 100644
index 0000000..5f647d0
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import android.security.keystore.Signature;
+
+/**
+ * @hide
+ * This parcelable constitutes and excerpt from the PackageManager's PackageInfo for the purpose of
+ * key attestation. It is part of the KeyAttestationApplicationId, which is used by
+ * keystore to identify the caller of the keystore API towards a remote party.
+ */
+parcelable KeyAttestationPackageInfo {
+ String packageName;
+
+ long versionCode;
+
+ Signature[] signatures;
+}
diff --git a/keystore/aaid/aidl/android/security/keystore/Signature.aidl b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
new file mode 100644
index 0000000..800499a
--- /dev/null
+++ b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+/**
+ * @hide
+ * Represents a signature data read from the package file. Extracted from from the PackageManager's
+ * PackageInfo for the purpose of key attestation. It is part of the KeyAttestationPackageInfo,
+ * which is used by keystore to identify the caller of the keystore API towards a remote party.
+ */
+parcelable Signature {
+ /**
+ * Represents signing certificate data associated with application package, signatures are
+ * expected to be a hex-encoded ASCII string representing valid X509 certificate.
+ */
+ byte[] data;
+}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 0f3488b..31c2eb2 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -28,8 +28,8 @@
import android.util.Log;
/**
- * @hide This is the client side for IKeystoreUserManager AIDL.
- * It shall only be used by the LockSettingsService.
+ * @hide This is the client side for IKeystoreMaintenance AIDL.
+ * It is used mainly by LockSettingsService.
*/
public class AndroidKeyStoreMaintenance {
private static final String TAG = "AndroidKeyStoreMaintenance";
@@ -66,7 +66,7 @@
}
/**
- * Informs Keystore 2.0 about removing a usergit mer
+ * Informs Keystore 2.0 about removing a user
*
* @param userId - Android user id of the user being removed
* @return 0 if successful or a {@code ResponseCode}
@@ -91,7 +91,7 @@
*
* @param userId - Android user id of the user
* @param password - a secret derived from the synthetic password provided by the
- * LockSettingService
+ * LockSettingsService
* @return 0 if successful or a {@code ResponseCode}
* @hide
*/
@@ -110,7 +110,7 @@
}
/**
- * Informs Keystore 2.0 that an app was uninstalled and the corresponding namspace is to
+ * Informs Keystore 2.0 that an app was uninstalled and the corresponding namespace is to
* be cleared.
*/
public static int clearNamespace(@Domain int domain, long namespace) {
@@ -172,10 +172,10 @@
* namespace.
*
* @return * 0 on success
- * * KEY_NOT_FOUND if the source did not exists.
+ * * KEY_NOT_FOUND if the source did not exist.
* * PERMISSION_DENIED if any of the required permissions was missing.
* * INVALID_ARGUMENT if the destination was occupied or any domain value other than
- * the allowed once were specified.
+ * the allowed ones was specified.
* * SYSTEM_ERROR if an unexpected error occurred.
*/
public static int migrateKeyNamespace(KeyDescriptor source, KeyDescriptor destination) {
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3efb41d..cf26937 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -163,12 +163,10 @@
Settings.Secure.CHARGING_VIBRATION_ENABLED,
Settings.Secure.ACCESSIBILITY_NON_INTERACTIVE_UI_TIMEOUT_MS,
Settings.Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS,
- Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
Settings.Secure.UI_NIGHT_MODE,
Settings.Secure.UI_NIGHT_MODE_CUSTOM_TYPE,
Settings.Secure.DARK_THEME_CUSTOM_START_TIME,
Settings.Secure.DARK_THEME_CUSTOM_END_TIME,
- Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
Settings.Secure.SKIP_DIRECTION,
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
Settings.Secure.BACK_GESTURE_INSET_SCALE_LEFT,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index f6c2f69..f78f202 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -242,9 +242,7 @@
Secure.ACCESSIBILITY_INTERACTIVE_UI_TIMEOUT_MS, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.USER_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SETUP_COMPLETE, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.TRUST_AGENTS_EXTEND_UNLOCK, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, JSON_OBJECT_VALIDATOR);
- VALIDATORS.put(Secure.LOCK_SCREEN_WHEN_TRUST_LOST, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.SKIP_GESTURE, BOOLEAN_VALIDATOR);
/*
* Only used if FeatureFlag "settings_skip_direction_mutable" is enabled.
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4e412bb..9ac30f3 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -180,6 +180,7 @@
"android.hidl.manager-V1.2-java",
"cbor-java",
"icu4j_calendar_astronomer",
+ "android.security.aaid_aidl-java",
"netd-client",
"overlayable_policy_aidl-java",
"SurfaceFlingerProperties",
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index 46f486d..f572845 100644
--- a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
+++ b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
@@ -311,7 +311,7 @@
@Nullable
private static synchronized IGateKeeperService getGatekeeperService() {
- final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
+ final IBinder service = ServiceManager.waitForService(Context.GATEKEEPER_SERVICE);
if (service == null) {
Slog.e(TAG, "Unable to acquire GateKeeperService");
return null;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0a02c49..ff959de 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -115,7 +115,6 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.EventLog;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
@@ -861,15 +860,11 @@
@Override // binder interface
public void systemReady() {
- if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
- EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
- }
checkWritePermission();
mHasSecureLockScreen = mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN);
migrateOldData();
- getGateKeeperService();
getAuthSecretHal();
mDeviceProvisionedObserver.onSystemReady();
@@ -1109,9 +1104,6 @@
}
private final void checkPasswordHavePermission() {
- if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
- EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
- }
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
}
@@ -1676,6 +1668,7 @@
+ PERMISSION);
}
}
+ credential.validateBasicRequirements();
final long identity = Binder.clearCallingIdentity();
try {
@@ -2239,17 +2232,6 @@
// credential has matched
mBiometricDeferredQueue.addPendingLockoutResetForUser(userId,
authResult.syntheticPassword.deriveGkPassword());
-
- // perform verifyChallenge with synthetic password which generates the real GK auth
- // token and response for the current user
- response = mSpManager.verifyChallenge(getGateKeeperService(),
- authResult.syntheticPassword, 0L /* challenge */, userId);
- if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
- // This shouldn't really happen: the unwrapping of SP succeeds, but SP doesn't
- // match the recorded GK password handle.
- Slog.wtf(TAG, "verifyChallenge with SP failed.");
- return VerifyCredentialResponse.ERROR;
- }
}
}
if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
@@ -2645,7 +2627,7 @@
return mGateKeeperService;
}
- final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
+ final IBinder service = ServiceManager.waitForService(Context.GATEKEEPER_SERVICE);
if (service != null) {
try {
service.linkToDeath(new GateKeeperDiedRecipient(), 0);
@@ -2883,7 +2865,7 @@
*
* Also maintains the invariants described in {@link SyntheticPasswordManager} by
* setting/clearing the protection (by the SP) on the user's auth-bound Keystore keys when the
- * LSKF is added/removed, respectively. If the new LSKF is nonempty, then the Gatekeeper auth
+ * LSKF is added/removed, respectively. If an LSKF is being added, then the Gatekeeper auth
* token is also refreshed.
*/
@GuardedBy("mSpManager")
@@ -2900,9 +2882,7 @@
// not needed by synchronizeUnifiedWorkChallengeForProfiles()
profilePasswords = null;
- if (mSpManager.hasSidForUser(userId)) {
- mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
- } else {
+ if (!mSpManager.hasSidForUser(userId)) {
mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
setKeystorePassword(sp.deriveKeyStorePassword(), userId);
@@ -3118,6 +3098,7 @@
private boolean setLockCredentialWithToken(LockscreenCredential credential, long tokenHandle,
byte[] token, int userId) {
boolean result;
+ credential.validateBasicRequirements();
synchronized (mSpManager) {
if (!mSpManager.hasEscrowData(userId)) {
throw new SecurityException("Escrow token is disabled on the current user");
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index f107d0b..df95c69 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -16,8 +16,6 @@
package com.android.server.locksettings;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import android.app.ActivityManager;
@@ -313,16 +311,8 @@
mLockPatternUtils.getRequestedPasswordMetrics(mCurrentUserId);
final int requiredComplexity =
mLockPatternUtils.getRequestedPasswordComplexity(mCurrentUserId);
- final List<PasswordValidationError> errors;
- if (credential.isPassword() || credential.isPin()) {
- errors = PasswordMetrics.validatePassword(requiredMetrics, requiredComplexity,
- credential.isPin(), credential.getCredential());
- } else {
- PasswordMetrics metrics = new PasswordMetrics(
- credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE);
- errors = PasswordMetrics.validatePasswordMetrics(
- requiredMetrics, requiredComplexity, metrics);
- }
+ final List<PasswordValidationError> errors =
+ PasswordMetrics.validateCredential(requiredMetrics, requiredComplexity, credential);
if (!errors.isEmpty()) {
getOutPrintWriter().println(
"New credential doesn't satisfy admin policies: " + errors.get(0));
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index e8fd6f8..7fec377 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -1602,7 +1602,7 @@
/** Destroy all weak token-based SP protectors for the given user. */
public void destroyAllWeakTokenBasedProtectors(int userId) {
List<Long> protectorIds =
- mStorage.listSyntheticPasswordProtectorsForUser(SECDISCARDABLE_NAME, userId);
+ mStorage.listSyntheticPasswordProtectorsForUser(SP_BLOB_NAME, userId);
for (long protectorId : protectorIds) {
SyntheticPasswordBlob blob = SyntheticPasswordBlob.fromBytes(loadState(SP_BLOB_NAME,
protectorId, userId));
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index c908acd..d5bc912 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -24,9 +24,10 @@
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.keymaster.IKeyAttestationApplicationIdProvider;
-import android.security.keymaster.KeyAttestationApplicationId;
-import android.security.keymaster.KeyAttestationPackageInfo;
+import android.security.keystore.IKeyAttestationApplicationIdProvider;
+import android.security.keystore.KeyAttestationApplicationId;
+import android.security.keystore.KeyAttestationPackageInfo;
+import android.security.keystore.Signature;
/**
* @hide
@@ -64,14 +65,25 @@
for (int i = 0; i < packageNames.length; ++i) {
PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
PackageManager.GET_SIGNATURES, userId);
- keyAttestationPackageInfos[i] = new KeyAttestationPackageInfo(packageNames[i],
- packageInfo.getLongVersionCode(), packageInfo.signatures);
+ KeyAttestationPackageInfo pInfo = new KeyAttestationPackageInfo();
+ pInfo.packageName = new String(packageNames[i]);
+ pInfo.versionCode = packageInfo.getLongVersionCode();
+ pInfo.signatures = new Signature[packageInfo.signatures.length];
+ for (int index = 0; index < packageInfo.signatures.length; index++) {
+ Signature sign = new Signature();
+ sign.data = packageInfo.signatures[index].toByteArray();
+ pInfo.signatures[index] = sign;
+ }
+
+ keyAttestationPackageInfos[i] = pInfo;
}
} catch (NameNotFoundException nnfe) {
throw new RemoteException(nnfe.getMessage());
} finally {
Binder.restoreCallingIdentity(token);
}
- return new KeyAttestationApplicationId(keyAttestationPackageInfos);
+ KeyAttestationApplicationId attestAppId = new KeyAttestationApplicationId();
+ attestAppId.packageInfos = keyAttestationPackageInfos;
+ return attestAppId;
}
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 36529d82..635e11b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -31,7 +31,6 @@
import android.app.trust.ITrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -42,11 +41,9 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
-import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -237,7 +234,6 @@
mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
private AlarmManager mAlarmManager;
private final Object mAlarmLock = new Object();
- private final SettingsObserver mSettingsObserver;
private final StrongAuthTracker mStrongAuthTracker;
@@ -279,7 +275,6 @@
mLockPatternUtils = injector.getLockPatternUtils();
mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mSettingsObserver = new SettingsObserver(mHandler);
}
@Override
@@ -307,103 +302,10 @@
}
}
- // Extend unlock config and logic
- private final class SettingsObserver extends ContentObserver {
- private final Uri TRUST_AGENTS_EXTEND_UNLOCK =
- Settings.Secure.getUriFor(Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK);
-
- private final Uri LOCK_SCREEN_WHEN_TRUST_LOST =
- Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST);
-
- private final boolean mIsAutomotive;
- private final ContentResolver mContentResolver;
- private boolean mTrustAgentsNonrenewableTrust;
- private boolean mLockWhenTrustLost;
-
- /**
- * Creates a settings observer
- *
- * @param handler The handler to run {@link #onChange} on, or null if none.
- */
- SettingsObserver(Handler handler) {
- super(handler);
-
- PackageManager packageManager = getContext().getPackageManager();
- mIsAutomotive = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
-
- mContentResolver = getContext().getContentResolver();
- updateContentObserver();
- }
-
- void updateContentObserver() {
- mContentResolver.unregisterContentObserver(this);
- mContentResolver.registerContentObserver(TRUST_AGENTS_EXTEND_UNLOCK,
- false /* notifyForDescendents */,
- this /* observer */,
- mCurrentUser);
- mContentResolver.registerContentObserver(LOCK_SCREEN_WHEN_TRUST_LOST,
- false /* notifyForDescendents */,
- this /* observer */,
- mCurrentUser);
-
- // Update the value immediately
- onChange(true /* selfChange */, TRUST_AGENTS_EXTEND_UNLOCK);
- onChange(true /* selfChange */, LOCK_SCREEN_WHEN_TRUST_LOST);
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- if (TRUST_AGENTS_EXTEND_UNLOCK.equals(uri)) {
- // Smart lock should only grant non-renewable trust. The only exception is for
- // automotive, where it can actively unlock the head unit.
- int defaultValue = mIsAutomotive ? 0 : 1;
-
- mTrustAgentsNonrenewableTrust =
- Settings.Secure.getIntForUser(
- mContentResolver,
- Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
- defaultValue,
- mCurrentUser) != 0;
- } else if (LOCK_SCREEN_WHEN_TRUST_LOST.equals(uri)) {
- mLockWhenTrustLost =
- Settings.Secure.getIntForUser(
- mContentResolver,
- Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
- 0 /* default */,
- mCurrentUser) != 0;
- }
- }
-
- boolean getTrustAgentsNonrenewableTrust() {
- return mTrustAgentsNonrenewableTrust;
- }
-
- boolean getLockWhenTrustLost() {
- return mLockWhenTrustLost;
- }
- }
-
- private void maybeLockScreen(int userId) {
- if (userId != mCurrentUser) {
- return;
- }
-
- if (mSettingsObserver.getLockWhenTrustLost()) {
- if (DEBUG) Slog.d(TAG, "Locking device because trust was lost");
- try {
- WindowManagerGlobal.getWindowManagerService().lockNow(null);
- } catch (RemoteException e) {
- Slog.e(TAG, "Error locking screen when trust was lost");
- }
-
- // If active unlocking is not allowed, cancel any pending trust timeouts because the
- // screen is already locked.
- TrustedTimeoutAlarmListener alarm = mTrustTimeoutAlarmListenerForUser.get(userId);
- if (alarm != null && mSettingsObserver.getTrustAgentsNonrenewableTrust()) {
- mAlarmManager.cancel(alarm);
- alarm.setQueued(false /* isQueued */);
- }
- }
+ // Automotive head units can be unlocked by a trust agent, even when the agent doesn't use
+ // FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE.
+ private boolean isAutomotive() {
+ return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}
private void scheduleTrustTimeout(boolean override, boolean isTrustableTimeout) {
@@ -600,12 +502,10 @@
synchronized (mUserTrustState) {
wasTrusted = (mUserTrustState.get(userId) == TrustState.TRUSTED);
wasTrustable = (mUserTrustState.get(userId) == TrustState.TRUSTABLE);
- boolean isAutomotive = getContext().getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_AUTOMOTIVE);
boolean renewingTrust = wasTrustable && (
(flags & TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0);
boolean canMoveToTrusted =
- alreadyUnlocked || isFromUnlock || renewingTrust || isAutomotive;
+ alreadyUnlocked || isFromUnlock || renewingTrust || isAutomotive();
boolean upgradingTrustForCurrentUser = (userId == mCurrentUser);
if (trustedByAtLeastOneAgent && wasTrusted) {
@@ -632,9 +532,7 @@
isNowTrusted, newlyUnlocked, userId, flags, getTrustGrantedMessages(userId));
if (isNowTrusted != wasTrusted) {
refreshDeviceLockedForUser(userId);
- if (!isNowTrusted) {
- maybeLockScreen(userId);
- } else {
+ if (isNowTrusted) {
boolean isTrustableTimeout =
(flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0;
// Every time we grant renewable trust we should override the idle trustable
@@ -1357,7 +1255,7 @@
for (int i = 0; i < mActiveAgents.size(); i++) {
AgentInfo info = mActiveAgents.valueAt(i);
if (info.userId == userId) {
- if (info.agent.isTrustableOrWaitingForDowngrade()) {
+ if (info.agent.isManagingTrust()) {
return true;
}
}
@@ -1855,9 +1753,7 @@
synchronized(mUsersUnlockedByBiometric) {
mUsersUnlockedByBiometric.put(userId, true);
}
- // In non-renewable trust mode we need to refresh trust state here, which will call
- // refreshDeviceLockedForUser()
- int updateTrustOnUnlock = mSettingsObserver.getTrustAgentsNonrenewableTrust() ? 1 : 0;
+ int updateTrustOnUnlock = isAutomotive() ? 0 : 1;
mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, userId,
updateTrustOnUnlock).sendToTarget();
mHandler.obtainMessage(MSG_REFRESH_TRUSTABLE_TIMERS_AFTER_AUTH, userId).sendToTarget();
@@ -1966,7 +1862,6 @@
break;
case MSG_SWITCH_USER:
mCurrentUser = msg.arg1;
- mSettingsObserver.updateContentObserver();
refreshDeviceLockedForUser(UserHandle.USER_ALL);
break;
case MSG_STOP_USER:
@@ -2196,7 +2091,6 @@
mLockPatternUtils.requireStrongAuth(
mStrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_TRUSTAGENT_EXPIRED, mUserId);
}
- maybeLockScreen(mUserId);
}
protected abstract void handleAlarm();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 34170fa..ab218a6 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5127,8 +5127,11 @@
boolean deviceWideOnly) {
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
- && (isSystemUid(caller) || hasCallingOrSelfPermission(
- permission.SET_INITIAL_LOCK)));
+ && (isSystemUid(caller)
+ // Accept any permission that ILockSettings#setLockCredential() accepts.
+ || hasCallingOrSelfPermission(permission.SET_INITIAL_LOCK)
+ || hasCallingOrSelfPermission(permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS)
+ || hasCallingOrSelfPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)));
return getPasswordMinimumMetricsUnchecked(userHandle, deviceWideOnly);
}
@@ -5725,20 +5728,17 @@
final int callingUid = caller.getUid();
final int userHandle = UserHandle.getUserId(callingUid);
final boolean isPin = PasswordMetrics.isNumericOnly(password);
+ final LockscreenCredential newCredential;
+ if (isPin) {
+ newCredential = LockscreenCredential.createPin(password);
+ } else {
+ newCredential = LockscreenCredential.createPasswordOrNone(password);
+ }
synchronized (getLockObject()) {
final PasswordMetrics minMetrics = getPasswordMinimumMetricsUnchecked(userHandle);
- final List<PasswordValidationError> validationErrors;
final int complexity = getAggregatedPasswordComplexityLocked(userHandle);
- // TODO: Consider changing validation API to take LockscreenCredential.
- if (password.isEmpty()) {
- validationErrors = PasswordMetrics.validatePasswordMetrics(
- minMetrics, complexity, new PasswordMetrics(CREDENTIAL_TYPE_NONE));
- } else {
- // TODO(b/120484642): remove getBytes() below
- validationErrors = PasswordMetrics.validatePassword(
- minMetrics, complexity, isPin, password.getBytes());
- }
-
+ final List<PasswordValidationError> validationErrors =
+ PasswordMetrics.validateCredential(minMetrics, complexity, newCredential);
if (!validationErrors.isEmpty()) {
Slogf.w(LOG_TAG, "Failed to reset password due to constraint violation: %s",
validationErrors.get(0));
@@ -5762,12 +5762,6 @@
// Don't do this with the lock held, because it is going to call
// back in to the service.
final long ident = mInjector.binderClearCallingIdentity();
- final LockscreenCredential newCredential;
- if (isPin) {
- newCredential = LockscreenCredential.createPin(password);
- } else {
- newCredential = LockscreenCredential.createPasswordOrNone(password);
- }
try {
if (tokenHandle == 0 || token == null) {
if (!mLockPatternUtils.setLockCredential(newCredential,
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 99a3b80..cc07cce 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -46,7 +46,6 @@
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_OPEN;
import static android.app.admin.DevicePolicyManager.WIFI_SECURITY_PERSONAL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
-import static android.app.admin.PasswordMetrics.computeForPasswordOrPin;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
@@ -5479,8 +5478,7 @@
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
- "abcdXYZ5".getBytes(), /* isPin */ false);
+ PasswordMetrics passwordMetricsNoSymbols = metricsForPassword("abcdXYZ5");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5507,8 +5505,7 @@
reset(mContext.spiedContext);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
- PasswordMetrics passwordMetricsWithSymbols = computeForPasswordOrPin(
- "abcd.XY5".getBytes(), /* isPin */ false);
+ PasswordMetrics passwordMetricsWithSymbols = metricsForPassword("abcd.XY5");
setActivePasswordState(passwordMetricsWithSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5564,7 +5561,7 @@
parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("184342".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("184342"));
// Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly
// on the parent admin)
@@ -5685,7 +5682,7 @@
// Set a work challenge and verify profile.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5710,7 +5707,7 @@
// Set a work challenge and verify profile.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
- .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("5156"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5735,7 +5732,7 @@
// Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("acbdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("acbdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5758,7 +5755,7 @@
// Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("1234".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("1234"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5783,7 +5780,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5806,7 +5803,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("51567548".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("51567548"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5831,7 +5828,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("abcdXYZ5"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -5854,7 +5851,7 @@
// Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
- .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
+ .thenReturn(metricsForPin("5156"));
assertThat(dpm.isActivePasswordSufficient()).isTrue();
assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
}
@@ -6909,7 +6906,7 @@
.thenReturn(CALLER_USER_HANDLE);
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("asdf"));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM);
}
@@ -6929,10 +6926,10 @@
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(CALLER_USER_HANDLE))
- .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("asdf"));
when(getServices().lockSettingsInternal
.getUserPasswordMetrics(parentUser.id))
- .thenReturn(computeForPasswordOrPin("parentUser".getBytes(), /* isPin */ false));
+ .thenReturn(metricsForPassword("parentUser"));
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
}
@@ -7654,15 +7651,13 @@
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE);
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
- "1234".getBytes(), /* isPin */ true);
+ PasswordMetrics passwordMetricsNoSymbols = metricsForPin("1234");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW);
assertThat(dpm.isActivePasswordSufficient()).isFalse();
reset(mContext.spiedContext);
- passwordMetricsNoSymbols = computeForPasswordOrPin(
- "84125312943a".getBytes(), /* isPin */ false);
+ passwordMetricsNoSymbols = metricsForPassword("84125312943a");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
// using isActivePasswordSufficient
@@ -8838,4 +8833,12 @@
assumeTrue("device doesn't support deprecated password APIs",
isDeprecatedPasswordApisSupported());
}
+
+ private static PasswordMetrics metricsForPassword(String password) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPassword(password));
+ }
+
+ private static PasswordMetrics metricsForPin(String pin) {
+ return PasswordMetrics.computeForCredential(LockscreenCredential.createPin(pin));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index d8e4fda..7189383 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -285,6 +285,7 @@
assertEquals(info.currentState, DEFAULT_DEVICE_STATE.getIdentifier());
}
+ @FlakyTest(bugId = 297949293)
@Test
public void getDeviceStateInfo_baseStateAndCommittedStateNotSet() throws RemoteException {
// Create a provider and a service without an initial base state.
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 60a033f..5a62d92 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -77,6 +77,26 @@
testSetCredentialFailsWithoutLockScreen(PRIMARY_USER_ID, newPassword("password"));
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetTooShortPatternFails() throws RemoteException {
+ mService.setLockCredential(newPattern("123"), nonePassword(), PRIMARY_USER_ID);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetTooShortPinFails() throws RemoteException {
+ mService.setLockCredential(newPin("123"), nonePassword(), PRIMARY_USER_ID);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetTooShortPassword() throws RemoteException {
+ mService.setLockCredential(newPassword("123"), nonePassword(), PRIMARY_USER_ID);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testSetPasswordWithInvalidChars() throws RemoteException {
+ mService.setLockCredential(newPassword("§µ¿¶¥£"), nonePassword(), PRIMARY_USER_ID);
+ }
+
@Test
public void testSetPatternPrimaryUser() throws RemoteException {
setAndVerifyCredential(PRIMARY_USER_ID, newPattern("123456789"));
@@ -94,7 +114,7 @@
@Test
public void testChangePatternPrimaryUser() throws RemoteException {
- testChangeCredential(PRIMARY_USER_ID, newPassword("!£$%^&*(())"), newPattern("1596321"));
+ testChangeCredential(PRIMARY_USER_ID, newPassword("password"), newPattern("1596321"));
}
@Test
@@ -185,7 +205,7 @@
assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID));
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
- setCredential(PRIMARY_USER_ID, newPassword("pwd"), primaryPassword);
+ setCredential(PRIMARY_USER_ID, newPassword("password"), primaryPassword);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
profilePassword, MANAGED_PROFILE_USER_ID, 0 /* flags */)
.getResponseCode());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index ce0347d..dee7780 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -215,12 +215,12 @@
@Test
public void testChangeCredentialKeepsAuthSecret() throws RemoteException {
LockscreenCredential password = newPassword("password");
- LockscreenCredential badPassword = newPassword("new");
+ LockscreenCredential newPassword = newPassword("newPassword");
initSpAndSetCredential(PRIMARY_USER_ID, password);
- mService.setLockCredential(badPassword, password, PRIMARY_USER_ID);
+ mService.setLockCredential(newPassword, password, PRIMARY_USER_ID);
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
- badPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
+ newPassword, PRIMARY_USER_ID, 0 /* flags */).getResponseCode());
// Check the same secret was passed each time
ArgumentCaptor<byte[]> secret = ArgumentCaptor.forClass(byte[].class);
diff --git a/tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt b/tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
similarity index 100%
rename from tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt
rename to tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt