summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/preloaded-classes14
-rw-r--r--core/api/current.txt3
-rw-r--r--core/api/system-current.txt2
-rw-r--r--core/java/Android.bp5
-rw-r--r--core/java/android/app/KeyguardManager.java29
-rw-r--r--core/java/android/app/admin/PasswordMetrics.java77
-rw-r--r--core/java/android/content/pm/Signature.aidl32
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl5
-rw-r--r--core/java/android/nfc/NfcAdapter.java92
-rw-r--r--core/java/android/nfc/flags.aconfig7
-rw-r--r--core/java/android/os/BatteryManager.java17
-rw-r--r--core/java/android/os/flags.aconfig7
-rw-r--r--core/java/android/provider/Settings.java14
-rw-r--r--core/java/android/security/keymaster/KeyAttestationApplicationId.java74
-rw-r--r--core/java/android/security/keymaster/KeyAttestationPackageInfo.java95
-rw-r--r--core/java/android/view/ViewGroup.java2
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java23
-rw-r--r--core/java/com/android/internal/widget/LockscreenCredential.java151
-rw-r--r--core/jni/android_util_Binder.cpp21
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/tests/coretests/src/android/app/KeyguardManagerTest.java16
-rw-r--r--core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java112
-rw-r--r--core/tests/coretests/src/android/view/ViewGroupTest.java19
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockscreenCredentialTest.java143
-rw-r--r--keystore/aaid/aidl/Android.bp31
-rw-r--r--keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl (renamed from core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl)20
-rw-r--r--keystore/aaid/aidl/android/security/keystore/KeyAttestationApplicationId.aidl31
-rw-r--r--keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl (renamed from core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl)21
-rw-r--r--keystore/aaid/aidl/android/security/keystore/Signature.aidl (renamed from core/java/android/security/keymaster/KeyAttestationApplicationId.aidl)17
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java14
-rw-r--r--media/java/android/media/AudioAttributes.java13
-rw-r--r--media/java/android/media/AudioMetadata.java19
-rw-r--r--media/java/android/media/tv/SectionRequest.java2
-rw-r--r--media/java/android/media/tv/SectionResponse.java2
-rw-r--r--media/java/android/media/tv/TableRequest.java2
-rw-r--r--media/java/android/media/tv/TableResponse.java2
-rw-r--r--media/jni/android_media_MediaDrm.cpp48
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java2
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java1
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/BatteryService.java8
-rw-r--r--services/core/java/com/android/server/content/SyncStorageEngine.java2
-rw-r--r--services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java2
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java33
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java14
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java2
-rw-r--r--services/core/java/com/android/server/om/OverlayManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/DexOptHelper.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageMetrics.java28
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java5
-rw-r--r--services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java24
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java122
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java32
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java335
-rw-r--r--tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt (renamed from tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt)0
60 files changed, 1156 insertions, 726 deletions
diff --git a/config/preloaded-classes b/config/preloaded-classes
index 1812c2bb61d6..fd4e3dfcaf95 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -6634,12 +6634,6 @@ android.security.Scrypt
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.AttestationUtils
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$1
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/api/current.txt b/core/api/current.txt
index 7ee12d1c3ae0..dd98aa569ddb 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29084,6 +29084,8 @@ package android.nfc {
method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
method public boolean isEnabled();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
method public boolean isSecureNfcEnabled();
method public boolean isSecureNfcSupported();
field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
@@ -32493,6 +32495,7 @@ package android.os {
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
field public static final int BATTERY_PROPERTY_CURRENT_NOW = 2; // 0x2
field public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5; // 0x5
+ field @FlaggedApi("android.os.state_of_health_public") public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10; // 0xa
field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_STATUS_CHARGING = 2; // 0x2
field public static final int BATTERY_STATUS_DISCHARGING = 3; // 0x3
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0e4a52401f38..147a37022b58 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10216,6 +10216,7 @@ package android.nfc {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
@@ -10315,7 +10316,6 @@ package android.os {
field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_CHARGING_POLICY = 9; // 0x9
field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_FIRST_USAGE_DATE = 8; // 0x8
field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_MANUFACTURING_DATE = 7; // 0x7
- field @RequiresPermission(android.Manifest.permission.BATTERY_STATS) public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10; // 0xa
field public static final int CHARGING_POLICY_ADAPTIVE_AC = 3; // 0x3
field public static final int CHARGING_POLICY_ADAPTIVE_AON = 2; // 0x2
field public static final int CHARGING_POLICY_ADAPTIVE_LONGLIFE = 4; // 0x4
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 5091b52f7fd0..70864d532986 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -23,11 +23,6 @@ filegroup {
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 7ed3a1d63e4f..6a51171b8f90 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -60,6 +60,7 @@ import com.android.internal.widget.IWeakEscrowTokenRemovedListener;
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 @@ public class KeyguardManager {
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 @@ public class KeyguardManager {
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 @@ public class KeyguardManager {
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 ab48791d43ef..dd311755bf3f 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_PASSW
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 @@ public final class PasswordMetrics implements Parcelable {
}
}
- 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 @@ public final class PasswordMetrics implements Parcelable {
};
/**
- * 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 @@ public final class PasswordMetrics implements Parcelable {
}
/**
- * 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 @@ public final class PasswordMetrics implements Parcelable {
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 @@ public final class PasswordMetrics implements Parcelable {
}
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 @@ public final class PasswordMetrics implements Parcelable {
}
/**
- * 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 @@ public final class PasswordMetrics implements Parcelable {
|| !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 36c127ad0384..000000000000
--- 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/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index a6d8cafe8263..0c95c2ec7a7a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -79,4 +79,9 @@ interface INfcAdapter
Map getTagIntentAppPreferenceForUser(int userId);
@JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
int setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow);
+
+ boolean isReaderOptionEnabled();
+ boolean isReaderOptionSupported();
+ @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
+ boolean enableReaderOption(boolean enable);
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 1307dfc2665e..46586308e3cf 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -17,6 +17,7 @@
package android.nfc;
import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -1826,6 +1827,97 @@ public final class NfcAdapter {
}
/**
+ * Sets NFC Reader option feature.
+ * <p>This API is for the Settings application.
+ * @return True if successful
+ * @hide
+ */
+ @SystemApi
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+ @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ public boolean enableReaderOption(boolean enable) {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.enableReaderOption(enable);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.enableReaderOption(enable);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Checks if the device supports NFC Reader option functionality.
+ *
+ * @return True if device supports NFC Reader option, false otherwise
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+ public boolean isReaderOptionSupported() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.isReaderOptionSupported();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.isReaderOptionSupported();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Checks NFC Reader option feature is enabled.
+ *
+ * @return True if NFC Reader option is enabled, false otherwise
+ * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
+ * @throws UnsupportedOperationException if device doesn't support
+ * NFC Reader option functionality. {@link #isReaderOptionSupported}
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
+ public boolean isReaderOptionEnabled() {
+ if (!sHasNfcFeature) {
+ throw new UnsupportedOperationException();
+ }
+ try {
+ return sService.isReaderOptionEnabled();
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ // Try one more time
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ return false;
+ }
+ try {
+ return sService.isReaderOptionEnabled();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to recover NFC Service.");
+ }
+ return false;
+ }
+ }
+
+ /**
* Enable NDEF Push feature.
* <p>This API is for the Settings application.
* @hide
diff --git a/core/java/android/nfc/flags.aconfig b/core/java/android/nfc/flags.aconfig
index e3faf3978856..55b0b4261763 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/core/java/android/nfc/flags.aconfig
@@ -6,3 +6,10 @@ flag {
description: "Flag for NFC mainline changes"
bug: "292140387"
}
+
+flag {
+ name: "enable_nfc_reader_option"
+ namespace: "nfc"
+ description: "Flag for NFC reader option API changes"
+ bug: "291187960"
+}
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 092923e927a3..6a4ec9b7605a 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,7 +16,10 @@
package android.os;
+import static android.os.Flags.FLAG_STATE_OF_HEALTH_PUBLIC;
+
import android.Manifest.permission;
+import android.annotation.FlaggedApi;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -354,17 +357,11 @@ public class BatteryManager {
public static final int BATTERY_PROPERTY_CHARGING_POLICY = 9;
/**
- *
- * Percentage representing the measured battery state of health (remaining
- * estimated full charge capacity relative to the rated capacity in %).
- *
- * <p class="note">
- * The sender must hold the {@link android.Manifest.permission#BATTERY_STATS} permission.
- *
- * @hide
+ * Percentage representing the measured battery state of health.
+ * This is the remaining estimated full charge capacity relative
+ * to the rated capacity in %.
*/
- @RequiresPermission(permission.BATTERY_STATS)
- @SystemApi
+ @FlaggedApi(FLAG_STATE_OF_HEALTH_PUBLIC)
public static final int BATTERY_PROPERTY_STATE_OF_HEALTH = 10;
private final Context mContext;
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 851aa6dce560..77229c44cc8d 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -1,6 +1,13 @@
package: "android.os"
flag {
+ name: "state_of_health_public"
+ namespace: "system_sw_battery"
+ description: "Feature flag for making state_of_health a public api."
+ bug: "288842045"
+}
+
+flag {
name: "disallow_cellular_null_ciphers_restriction"
namespace: "cellular_security"
description: "Guards a new UserManager user restriction that admins can use to require cellular encryption on their managed devices."
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index baeb1aa71207..9cdb9cefdc43 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10442,20 +10442,6 @@ public final class Settings {
"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/KeyAttestationApplicationId.java b/core/java/android/security/keymaster/KeyAttestationApplicationId.java
deleted file mode 100644
index 670f30e1b04b..000000000000
--- 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.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
deleted file mode 100644
index c0b8d8dfd4d9..000000000000
--- 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 0d0bfe3b8ab9..d70296353ff6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2536,7 +2536,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
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 490ec35d1482..a1f8de41cfce 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -96,7 +96,7 @@ public class LockPatternUtils {
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;
@@ -171,7 +171,6 @@ public class LockPatternUtils {
*/
public static final int USER_FRP = UserHandle.USER_NULL + 1;
- public final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
@@ -597,16 +596,6 @@ public class LockPatternUtils {
}
/**
- * Return true if the user has ever chosen a pattern. This is true even if the pattern is
- * currently cleared.
- *
- * @return True if the user has ever chosen a pattern.
- */
- public boolean isPatternEverChosen(int userId) {
- return getBoolean(PATTERN_EVER_CHOSEN_KEY, false, userId);
- }
-
- /**
* Returns the length of the PIN set by a particular user.
* @param userId user id of the user whose pin length we have to return
* @return
@@ -639,13 +628,6 @@ public class LockPatternUtils {
return false;
}
}
- /**
- * Records that the user has chosen a pattern at some time, even if the pattern is
- * currently cleared.
- */
- public void reportPatternWasChosen(int userId) {
- setBoolean(PATTERN_EVER_CHOSEN_KEY, true, userId);
- }
/**
* Used by device policy manager to validate the current password
@@ -771,7 +753,6 @@ public class LockPatternUtils {
* 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 +760,6 @@ public class LockPatternUtils {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
- newCredential.checkLength();
try {
if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
@@ -1543,7 +1523,6 @@ public class LockPatternUtils {
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 03e7fd1c7403..c88763ce6c97 100644
--- a/core/java/com/android/internal/widget/LockscreenCredential.java
+++ b/core/java/com/android/internal/widget/LockscreenCredential.java
@@ -60,10 +60,24 @@ import java.util.Objects;
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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
* 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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
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 class LockscreenCredential implements Parcelable, AutoCloseable {
*/
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 class LockscreenCredential implements Parcelable, AutoCloseable {
*/
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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
/**
* 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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
}
/**
- * 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 class LockscreenCredential implements Parcelable, AutoCloseable {
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 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
@Override
public LockscreenCredential createFromParcel(Parcel source) {
- return new LockscreenCredential(source.readInt(), source.createByteArray());
+ return new LockscreenCredential(source.readInt(), source.createByteArray(),
+ source.readBoolean());
}
@Override
@@ -346,7 +388,7 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
@Override
public int hashCode() {
// Effective Java — Always override hashCode when you override equals
- return Objects.hash(mType, Arrays.hashCode(mCredential));
+ return Objects.hash(mType, Arrays.hashCode(mCredential), mHasInvalidChars);
}
@Override
@@ -354,20 +396,45 @@ public class LockscreenCredential implements Parcelable, AutoCloseable {
if (o == this) return true;
if (!(o instanceof LockscreenCredential)) return false;
final LockscreenCredential other = (LockscreenCredential) o;
- return mType == other.mType && Arrays.equals(mCredential, other.mCredential);
+ 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 55382cc1d380..bfd80a9e4f74 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -157,12 +157,8 @@ static struct thread_dispatch_offsets_t
// ****************************************************************************
// ****************************************************************************
-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 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
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_getLocalObjectCount(JNIEnv* env, jobject clazz)
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 @@ static void BinderProxy_destroy(void* rawNativeData)
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 58f97b08f2e3..93048ea4fc85 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 958906c36d05..ed8b2887ac79 100644
--- a/core/tests/coretests/src/android/app/KeyguardManagerTest.java
+++ b/core/tests/coretests/src/android/app/KeyguardManagerTest.java
@@ -174,6 +174,22 @@ public class KeyguardManagerTest {
}
@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 c9e02f8a998d..33e81c163b4e 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_SOMETHING;
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 android.platform.test.annotations.Presubmit;
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 @@ public class PasswordMetricsTest {
@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 @@ public class PasswordMetricsTest {
@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 @@ public class PasswordMetricsTest {
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 b37c8fd8c34e..bce3f3e8f2e1 100644
--- a/core/tests/coretests/src/android/view/ViewGroupTest.java
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -49,11 +49,11 @@ public class ViewGroupTest {
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 @@ public class ViewGroupTest {
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 @@ public class ViewGroupTest {
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 @@ public class ViewGroupTest {
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 a47868d0a524..5692742f7248 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 java.util.Arrays;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
-public class LockscreenCredentialTest extends AndroidTestCase {
+import java.util.Arrays;
- public void testEmptyCredential() {
- LockscreenCredential empty = LockscreenCredential.createNone();
+@RunWith(AndroidJUnit4.class)
+public class LockscreenCredentialTest {
- assertTrue(empty.isNone());
- assertEquals(0, empty.size());
- assertNotNull(empty.getCredential());
+ @Test
+ public void testNoneCredential() {
+ LockscreenCredential none = LockscreenCredential.createNone();
- assertFalse(empty.isPin());
- assertFalse(empty.isPassword());
- assertFalse(empty.isPattern());
+ assertTrue(none.isNone());
+ assertEquals(0, none.size());
+ assertArrayEquals(new byte[0], none.getCredential());
+
+ 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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
LockscreenCredential.createPasswordOrNone("abcd"));
}
+ @Test
public void testPinOrNoneCredential() {
assertEquals(LockscreenCredential.createNone(),
LockscreenCredential.createPinOrNone(null));
@@ -98,6 +139,35 @@ public class LockscreenCredentialTest extends AndroidTestCase {
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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
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 @@ public class LockscreenCredentialTest extends AndroidTestCase {
.isEqualTo(expectedHash);
}
+ @Test
public void testPasswordToHistoryHashInvalidInput() {
String password = "1234";
LockscreenCredential credential = LockscreenCredential.createPassword(password);
@@ -221,6 +308,7 @@ public class LockscreenCredentialTest extends AndroidTestCase {
.isNull();
}
+ @Test
public void testLegacyPasswordToHash() {
String password = "1234";
String salt = "6d5331dd120077a0";
@@ -233,6 +321,7 @@ public class LockscreenCredentialTest extends AndroidTestCase {
.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 000000000000..97acfb4ea4c3
--- /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/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
index dbffd5f57ce2..c360cb8f281a 100644
--- a/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
+++ b/keystore/aaid/aidl/android/security/keystore/IKeyAttestationApplicationIdProvider.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2016, The Android Open Source Project
+ * 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.
@@ -14,19 +14,15 @@
* limitations under the License.
*/
-package android.security.keymaster;
+package android.security.keystore;
-import android.security.keymaster.KeyAttestationApplicationId;
-import android.security.keymaster.KeyAttestationPackageInfo;
-import android.content.pm.Signature;
+import android.security.keystore.KeyAttestationApplicationId;
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
+/** @hide */
interface IKeyAttestationApplicationIdProvider {
- /* keep in sync with /system/security/keystore/keystore_attestation_id.cpp */
+ /**
+ * 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 000000000000..c33e8309b2f2
--- /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/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
index f8b843bc032f..5f647d0b1abe 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.aidl
+++ b/keystore/aaid/aidl/android/security/keystore/KeyAttestationPackageInfo.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, The Android Open Source Project
+ * 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.
@@ -14,9 +14,20 @@
* limitations under the License.
*/
-package android.security.keymaster;
+package android.security.keystore;
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
+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 cpp_header "keystore/KeyAttestationPackageInfo.h";
+parcelable KeyAttestationPackageInfo {
+ String packageName;
+
+ long versionCode;
+
+ Signature[] signatures;
+}
diff --git a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
index 9f6ff58ed5ce..800499a13355 100644
--- a/core/java/android/security/keymaster/KeyAttestationApplicationId.aidl
+++ b/keystore/aaid/aidl/android/security/keystore/Signature.aidl
@@ -14,9 +14,18 @@
* limitations under the License.
*/
-package android.security.keymaster;
+package android.security.keystore;
-/* The cpp_header is relative to system/security/keystore/include
- * Link against libkeystore_binder to make use of the native implementation of this Parcelable.
+/**
+ * @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 KeyAttestationApplicationId cpp_header "keystore/KeyAttestationApplicationId.h";
+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 0f3488bbe8d1..31c2eb2efaed 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -28,8 +28,8 @@ import android.system.keystore2.ResponseCode;
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 @@ public class AndroidKeyStoreMaintenance {
}
/**
- * 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 @@ public class AndroidKeyStoreMaintenance {
*
* @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 @@ public class AndroidKeyStoreMaintenance {
}
/**
- * 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 @@ public class AndroidKeyStoreMaintenance {
* 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/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index b0cdb0554c11..1d668681f80c 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -875,18 +875,7 @@ public final class AudioAttributes implements Parcelable {
/**
* Sets the attribute describing what is the intended use of the audio signal,
* such as alarm or ringtone.
- * @param usage one of {@link AttributeSdkUsage#USAGE_UNKNOWN},
- * {@link AttributeSdkUsage#USAGE_MEDIA},
- * {@link AttributeSdkUsage#USAGE_VOICE_COMMUNICATION},
- * {@link AttributeSdkUsage#USAGE_VOICE_COMMUNICATION_SIGNALLING},
- * {@link AttributeSdkUsage#USAGE_ALARM}, {@link AudioAttributes#USAGE_NOTIFICATION},
- * {@link AttributeSdkUsage#USAGE_NOTIFICATION_RINGTONE},
- * {@link AttributeSdkUsage#USAGE_NOTIFICATION_EVENT},
- * {@link AttributeSdkUsage#USAGE_ASSISTANT},
- * {@link AttributeSdkUsage#USAGE_ASSISTANCE_ACCESSIBILITY},
- * {@link AttributeSdkUsage#USAGE_ASSISTANCE_NAVIGATION_GUIDANCE},
- * {@link AttributeSdkUsage#USAGE_ASSISTANCE_SONIFICATION},
- * {@link AttributeSdkUsage#USAGE_GAME}.
+ * @param usage the usage to set.
* @return the same Builder instance.
*/
public Builder setUsage(@AttributeSdkUsage int usage) {
diff --git a/media/java/android/media/AudioMetadata.java b/media/java/android/media/AudioMetadata.java
index 0f962f9e9d4b..4e61549a5e5a 100644
--- a/media/java/android/media/AudioMetadata.java
+++ b/media/java/android/media/AudioMetadata.java
@@ -226,16 +226,15 @@ public final class AudioMetadata {
*
* An Integer value representing presentation content classifier.
*
- * @see AudioPresentation.ContentClassifier
- * One of {@link AudioPresentation#CONTENT_UNKNOWN},
- * {@link AudioPresentation#CONTENT_MAIN},
- * {@link AudioPresentation#CONTENT_MUSIC_AND_EFFECTS},
- * {@link AudioPresentation#CONTENT_VISUALLY_IMPAIRED},
- * {@link AudioPresentation#CONTENT_HEARING_IMPAIRED},
- * {@link AudioPresentation#CONTENT_DIALOG},
- * {@link AudioPresentation#CONTENT_COMMENTARY},
- * {@link AudioPresentation#CONTENT_EMERGENCY},
- * {@link AudioPresentation#CONTENT_VOICEOVER}.
+ * @see AudioPresentation#CONTENT_UNKNOWN
+ * @see AudioPresentation#CONTENT_MAIN
+ * @see AudioPresentation#CONTENT_MUSIC_AND_EFFECTS
+ * @see AudioPresentation#CONTENT_VISUALLY_IMPAIRED
+ * @see AudioPresentation#CONTENT_HEARING_IMPAIRED
+ * @see AudioPresentation#CONTENT_DIALOG
+ * @see AudioPresentation#CONTENT_COMMENTARY
+ * @see AudioPresentation#CONTENT_EMERGENCY
+ * @see AudioPresentation#CONTENT_VOICEOVER
*/
@NonNull public static final Key<Integer> KEY_PRESENTATION_CONTENT_CLASSIFIER =
createKey("presentation-content-classifier", Integer.class);
diff --git a/media/java/android/media/tv/SectionRequest.java b/media/java/android/media/tv/SectionRequest.java
index 078e83222e4e..ec0d7f7a2ce4 100644
--- a/media/java/android/media/tv/SectionRequest.java
+++ b/media/java/android/media/tv/SectionRequest.java
@@ -81,7 +81,7 @@ public final class SectionRequest extends BroadcastInfoRequest implements Parcel
/**
* Gets the version number of requested session. If it is null, value will be -1.
* <p>The consistency of version numbers between request and response depends on
- * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
* REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
* different from the version of the request. Otherwise, response with a different version from
* its request will be considered invalid.
diff --git a/media/java/android/media/tv/SectionResponse.java b/media/java/android/media/tv/SectionResponse.java
index f38ea9dfac99..10333fe424a6 100644
--- a/media/java/android/media/tv/SectionResponse.java
+++ b/media/java/android/media/tv/SectionResponse.java
@@ -76,7 +76,7 @@ public final class SectionResponse extends BroadcastInfoResponse implements Parc
/**
* Gets the Version number of requested session. If it is null, value will be -1.
* <p>The consistency of version numbers between request and response depends on
- * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
* REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
* different from the version of the request. Otherwise, response with a different version from
* its request will be considered invalid.
diff --git a/media/java/android/media/tv/TableRequest.java b/media/java/android/media/tv/TableRequest.java
index d9587f6ac089..06df07fbc899 100644
--- a/media/java/android/media/tv/TableRequest.java
+++ b/media/java/android/media/tv/TableRequest.java
@@ -129,7 +129,7 @@ public final class TableRequest extends BroadcastInfoRequest implements Parcelab
/**
* Gets the version number of requested table. If it is null, value will be -1.
* <p>The consistency of version numbers between request and response depends on
- * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
* REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
* different from the version of the request. Otherwise, response with a different version from
* its request will be considered invalid.
diff --git a/media/java/android/media/tv/TableResponse.java b/media/java/android/media/tv/TableResponse.java
index c4fc26ef1932..1daf452fa422 100644
--- a/media/java/android/media/tv/TableResponse.java
+++ b/media/java/android/media/tv/TableResponse.java
@@ -269,7 +269,7 @@ public final class TableResponse extends BroadcastInfoResponse implements Parcel
/**
* Gets the version number of requested table. If it is null, value will be -1.
* <p>The consistency of version numbers between request and response depends on
- * {@link BroadcastInfoRequest.RequestOption}. If the request has RequestOption value
+ * {@link BroadcastInfoRequest#getOption()}. If the request has RequestOption value
* REQUEST_OPTION_AUTO_UPDATE, then the response may be set to the latest version which may be
* different from the version of the request. Otherwise, response with a different version from
* its request will be considered invalid.
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index c616b84fa6fb..1c25080939da 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -38,6 +38,8 @@
#include <mediadrm/IDrmMetricsConsumer.h>
#include <mediadrm/IDrm.h>
#include <utils/Vector.h>
+#include <map>
+#include <string>
using ::android::os::PersistableBundle;
namespace drm = ::android::hardware::drm;
@@ -193,6 +195,11 @@ struct LogMessageFields {
jclass classId;
};
+struct DrmExceptionFields {
+ jmethodID init;
+ jclass classId;
+};
+
struct fields_t {
jfieldID context;
jmethodID post_event;
@@ -215,6 +222,7 @@ struct fields_t {
jclass parcelCreatorClassId;
KeyStatusFields keyStatus;
LogMessageFields logMessage;
+ std::map<std::string, DrmExceptionFields> exceptionCtors;
};
static fields_t gFields;
@@ -245,18 +253,32 @@ jobject hidlLogMessagesToJavaList(JNIEnv *env, const Vector<drm::V1_4::LogMessag
return arrayList;
}
-int drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
+void resolveDrmExceptionCtor(JNIEnv *env, const char *className) {
+ jclass clazz;
+ jmethodID init;
+ FIND_CLASS(clazz, className);
+ GET_METHOD_ID(init, clazz, "<init>", "(Ljava/lang/String;III)V");
+ gFields.exceptionCtors[std::string(className)] = {
+ .init = init,
+ .classId = static_cast<jclass>(env->NewGlobalRef(clazz))
+ };
+}
+
+void drmThrowException(JNIEnv* env, const char *className, const DrmStatus &err, const char *msg) {
using namespace android::jnihelp;
- jstring _detailMessage = CreateExceptionMsg(env, msg);
- int _status = ThrowException(env, className, "(Ljava/lang/String;III)V",
- _detailMessage,
- err.getCdmErr(),
- err.getOemErr(),
- err.getContext());
- if (_detailMessage != NULL) {
- env->DeleteLocalRef(_detailMessage);
+
+ if (gFields.exceptionCtors.count(std::string(className)) == 0) {
+ jniThrowException(env, className, msg);
+ } else {
+ jstring _detailMessage = CreateExceptionMsg(env, msg);
+ jobject exception = env->NewObject(gFields.exceptionCtors[std::string(className)].classId,
+ gFields.exceptionCtors[std::string(className)].init, _detailMessage,
+ err.getCdmErr(), err.getOemErr(), err.getContext());
+ env->Throw(static_cast<jthrowable>(exception));
+ if (_detailMessage != NULL) {
+ env->DeleteLocalRef(_detailMessage);
+ }
}
- return _status;
}
} // namespace anonymous
@@ -952,6 +974,10 @@ static void android_media_MediaDrm_native_init(JNIEnv *env) {
FIND_CLASS(clazz, "android/media/MediaDrm$LogMessage");
gFields.logMessage.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
GET_METHOD_ID(gFields.logMessage.init, clazz, "<init>", "(JILjava/lang/String;)V");
+
+ resolveDrmExceptionCtor(env, "android/media/NotProvisionedException");
+ resolveDrmExceptionCtor(env, "android/media/ResourceBusyException");
+ resolveDrmExceptionCtor(env, "android/media/DeniedByServerException");
}
static void android_media_MediaDrm_native_setup(
@@ -2192,4 +2218,4 @@ static const JNINativeMethod gMethods[] = {
int register_android_media_Drm(JNIEnv *env) {
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaDrm", gMethods, NELEM(gMethods));
-}
+} \ No newline at end of file
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3efb41dbfe5c..cf26937cbd88 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 @@ public class SecureSettings {
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 f6c2f6918739..f78f2028d7b6 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 @@ public class SecureSettingsValidators {
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/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index b404465a8cce..b19d3495c217 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -961,7 +961,6 @@ public class SettingsBackupAgent extends BackupAgentHelper {
lockPatternUtils.setOwnerInfo(value, userId);
break;
case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
- lockPatternUtils.reportPatternWasChosen(userId);
lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
break;
case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4e412bbe67df..9ac30f334d0b 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -180,6 +180,7 @@ java_library_static {
"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/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index d94f4f22f2c9..5b496f4766b3 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import static android.os.Flags.stateOfHealthPublic;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import static com.android.server.health.Utils.copyV1Battery;
@@ -27,7 +28,6 @@ import android.app.BroadcastOptions;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.database.ContentObserver;
import android.hardware.health.HealthInfo;
import android.hardware.health.V2_1.BatteryCapacityLevel;
@@ -1316,10 +1316,14 @@ public final class BatteryService extends SystemService {
@Override
public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
switch (id) {
+ case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH:
+ if (stateOfHealthPublic()) {
+ break;
+ }
+
case BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE:
case BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE:
case BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY:
- case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH:
mContext.enforceCallingPermission(
android.Manifest.permission.BATTERY_STATS, null);
break;
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index b890bbd65b95..eae417e1e838 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -1845,7 +1845,7 @@ public class SyncStorageEngine {
private void parseListenForTickles(TypedXmlPullParser parser) {
int userId = 0;
try {
- parser.getAttributeInt(null, XML_ATTR_USER);
+ userId = parser.getAttributeInt(null, XML_ATTR_USER);
} catch (XmlPullParserException e) {
Slog.e(TAG, "error parsing the user for listen-for-tickles", e);
}
diff --git a/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java b/services/core/java/com/android/server/locksettings/BiometricDeferredQueue.java
index 46f486d875b6..f572845dc214 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 @@ public class BiometricDeferredQueue {
@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 0a02c49192b9..8547c96e13af 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.system.keystore2.Domain;
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 @@ public class LockSettingsService extends ILockSettings.Stub {
@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 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private final void checkPasswordHavePermission() {
- if (mContext.checkCallingOrSelfPermission(PERMISSION) != PERMISSION_GRANTED) {
- EventLog.writeEvent(0x534e4554, "28251513", getCallingUid(), ""); // SafetyNet
- }
mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsHave");
}
@@ -1676,6 +1668,7 @@ public class LockSettingsService extends ILockSettings.Stub {
+ PERMISSION);
}
}
+ credential.validateBasicRequirements();
final long identity = Binder.clearCallingIdentity();
try {
@@ -1774,10 +1767,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
private void onPostPasswordChanged(LockscreenCredential newCredential, int userHandle) {
- if (newCredential.isPattern()) {
- setBoolean(LockPatternUtils.PATTERN_EVER_CHOSEN_KEY, true, userHandle);
- }
-
updatePasswordHistory(newCredential, userHandle);
mContext.getSystemService(TrustManager.class).reportEnabledTrustAgentsChanged(userHandle);
}
@@ -2239,17 +2228,6 @@ public class LockSettingsService extends ILockSettings.Stub {
// 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 +2623,7 @@ public class LockSettingsService extends ILockSettings.Stub {
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 +2861,7 @@ public class LockSettingsService extends ILockSettings.Stub {
*
* 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 +2878,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// 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 +3094,7 @@ public class LockSettingsService extends ILockSettings.Stub {
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 f107d0bf9932..df95c69e7271 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 @@ class LockSettingsShellCommand extends ShellCommand {
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 e8fd6f88359c..7fec377b3e9e 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 @@ class SyntheticPasswordManager {
/** 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/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 2f9536ff6427..23532c1b4eb3 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -261,6 +261,8 @@ public final class OverlayManagerService extends SystemService {
private final OverlayActorEnforcer mActorEnforcer;
+ private int mPrevStartedUserId = -1;
+
public OverlayManagerService(@NonNull final Context context) {
super(context);
try {
@@ -338,6 +340,10 @@ public final class OverlayManagerService extends SystemService {
}
private void onStartUser(@UserIdInt int newUserId) {
+ // Do nothing when start a user that is the same as the one started previously.
+ if (newUserId == mPrevStartedUserId) {
+ return;
+ }
try {
traceBegin(TRACE_TAG_RRO, "OMS#onStartUser " + newUserId);
// ensure overlays in the settings are up-to-date, and propagate
@@ -348,6 +354,7 @@ public final class OverlayManagerService extends SystemService {
} finally {
traceEnd(TRACE_TAG_RRO);
}
+ mPrevStartedUserId = newUserId;
}
private static String[] getDefaultOverlayPackages() {
diff --git a/services/core/java/com/android/server/pm/DexOptHelper.java b/services/core/java/com/android/server/pm/DexOptHelper.java
index 39cd88810961..8bd2982d1ead 100644
--- a/services/core/java/com/android/server/pm/DexOptHelper.java
+++ b/services/core/java/com/android/server/pm/DexOptHelper.java
@@ -1050,7 +1050,7 @@ public final class DexOptHelper {
context.unregisterReceiver(this);
artManager.scheduleBackgroundDexoptJob();
}
- }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }, new IntentFilter(Intent.ACTION_LOCKED_BOOT_COMPLETED));
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 80d6ebbd90b3..85e11d66737a 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -34,8 +34,11 @@ import java.io.File;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
@@ -155,10 +158,27 @@ final class PackageMetrics {
private long getApksSize(File apkDir) {
// TODO(b/249294752): also count apk sizes for failed installs
final AtomicLong apksSize = new AtomicLong();
- try (Stream<Path> walkStream = Files.walk(apkDir.toPath())) {
- walkStream.filter(p -> p.toFile().isFile()
- && ApkLiteParseUtils.isApkFile(p.toFile())).forEach(
- f -> apksSize.addAndGet(f.toFile().length()));
+ try {
+ Files.walkFileTree(apkDir.toPath(), new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
+ throws IOException {
+ if (dir.equals(apkDir.toPath())) {
+ return FileVisitResult.CONTINUE;
+ } else {
+ return FileVisitResult.SKIP_SUBTREE;
+ }
+ }
+
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException {
+ if (file.toFile().isFile() && ApkLiteParseUtils.isApkFile(file.toFile())) {
+ apksSize.addAndGet(file.toFile().length());
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ });
} catch (IOException e) {
// ignore
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index f0bf1ea80570..d0c346a63889 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -334,7 +334,10 @@ public class ArtStatsLogUtils {
ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN),
cancellationReason,
durationMs,
- 0); // deprecated, used to be durationIncludingSleepMs
+ 0, // deprecated, used to be durationIncludingSleepMs
+ 0, // optimizedPackagesCount
+ 0, // packagesDependingOnBootClasspathCount
+ 0); // totalPackagesCount
}
}
}
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index c908acdd1d6c..d5bc91278aa8 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.content.pm.PackageManager.NameNotFoundException;
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 @@ public class KeyAttestationApplicationIdProviderService
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 36529d824f41..635e11be3a16 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.ITrustListener;
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.pm.UserInfo;
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 @@ public class TrustManagerService extends SystemService {
mIdleTrustableTimeoutAlarmListenerForUser = new SparseArray<>();
private AlarmManager mAlarmManager;
private final Object mAlarmLock = new Object();
- private final SettingsObserver mSettingsObserver;
private final StrongAuthTracker mStrongAuthTracker;
@@ -279,7 +275,6 @@ public class TrustManagerService extends SystemService {
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 @@ public class TrustManagerService extends SystemService {
}
}
- // 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 @@ public class TrustManagerService extends SystemService {
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 @@ public class TrustManagerService extends SystemService {
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 @@ public class TrustManagerService extends SystemService {
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 @@ public class TrustManagerService extends SystemService {
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 @@ public class TrustManagerService extends SystemService {
break;
case MSG_SWITCH_USER:
mCurrentUser = msg.arg1;
- mSettingsObserver.updateContentObserver();
refreshDeviceLockedForUser(UserHandle.USER_ALL);
break;
case MSG_STOP_USER:
@@ -2196,7 +2091,6 @@ public class TrustManagerService extends SystemService {
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 34170fa4c8b5..ab218a671823 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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
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 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// 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 99a3b808e082..cc07ccefa119 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_ENTERPRISE_EAP
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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
reset(mContext.spiedContext);
- PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin(
- "abcdXYZ5".getBytes(), /* isPin */ false);
+ PasswordMetrics passwordMetricsNoSymbols = metricsForPassword("abcdXYZ5");
setActivePasswordState(passwordMetricsNoSymbols);
assertThat(dpm.isActivePasswordSufficient()).isTrue();
@@ -5507,8 +5505,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// 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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
.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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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 @@ public class DevicePolicyManagerTest extends DpmTestBase {
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 d8e4fdae5a34..7189383d180e 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 @@ public final class DeviceStateManagerServiceTest {
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 60a033fde427..5a62d92e8e12 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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
@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 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
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 ce0347dbe4ac..dee77806e4f3 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 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
@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/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
new file mode 100644
index 000000000000..949f8e7a6ab0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/LockdownVpnTrackerTest.java
@@ -0,0 +1,335 @@
+/*
+ * 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 com.android.server.net;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkInfo;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.text.TextUtils;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.server.connectivity.Vpn;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LockdownVpnTrackerTest {
+ private static final NetworkCapabilities TEST_CELL_NC = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ private static final LinkProperties TEST_CELL_LP = new LinkProperties();
+
+ static {
+ TEST_CELL_LP.setInterfaceName("rmnet0");
+ TEST_CELL_LP.addLinkAddress(new LinkAddress("192.0.2.2/25"));
+ }
+
+ // Use a context wrapper instead of a mock since LockdownVpnTracker builds notifications which
+ // is tedious and currently unnecessary to mock.
+ private final Context mContext = new ContextWrapper(InstrumentationRegistry.getContext()) {
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
+ if (Context.NOTIFICATION_SERVICE.equals(name)) return mNotificationManager;
+
+ return super.getSystemService(name);
+ }
+ };
+ @Mock private ConnectivityManager mCm;
+ @Mock private Vpn mVpn;
+ @Mock private NotificationManager mNotificationManager;
+ @Mock private NetworkInfo mVpnNetworkInfo;
+ @Mock private VpnConfig mVpnConfig;
+ @Mock private Network mNetwork;
+ @Mock private Network mNetwork2;
+ @Mock private Network mVpnNetwork;
+
+ private HandlerThread mHandlerThread;
+ private Handler mHandler;
+ private VpnProfile mProfile;
+
+ private VpnProfile createTestVpnProfile() {
+ final String profileName = "testVpnProfile";
+ final VpnProfile profile = new VpnProfile(profileName);
+ profile.name = "My VPN";
+ profile.server = "192.0.2.1";
+ profile.dnsServers = "8.8.8.8";
+ profile.ipsecIdentifier = "My ipsecIdentifier";
+ profile.ipsecSecret = "My PSK";
+ profile.type = VpnProfile.TYPE_IKEV2_IPSEC_PSK;
+
+ return profile;
+ }
+
+ private NetworkCallback getDefaultNetworkCallback() {
+ final ArgumentCaptor<NetworkCallback> callbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mCm).registerSystemDefaultNetworkCallback(callbackCaptor.capture(), eq(mHandler));
+ return callbackCaptor.getValue();
+ }
+
+ private NetworkCallback getVpnNetworkCallback() {
+ final ArgumentCaptor<NetworkCallback> callbackCaptor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), callbackCaptor.capture(), eq(mHandler));
+ return callbackCaptor.getValue();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mHandlerThread = new HandlerThread("LockdownVpnTrackerTest");
+ mHandlerThread.start();
+ mHandler = mHandlerThread.getThreadHandler();
+
+ doReturn(mVpnNetworkInfo).when(mVpn).getNetworkInfo();
+ doReturn(false).when(mVpnNetworkInfo).isConnectedOrConnecting();
+ doReturn(mVpnConfig).when(mVpn).getLegacyVpnConfig();
+ // mVpnConfig is a mock but the production code will try to add addresses in this array
+ // assuming it's non-null, so it needs to be initialized.
+ mVpnConfig.addresses = new ArrayList<>();
+
+ mProfile = createTestVpnProfile();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mHandlerThread != null) {
+ mHandlerThread.quitSafely();
+ mHandlerThread.join();
+ }
+ }
+
+ private LockdownVpnTracker initAndVerifyLockdownVpnTracker() {
+ final LockdownVpnTracker lockdownVpnTracker =
+ new LockdownVpnTracker(mContext, mHandler, mVpn, mProfile);
+ lockdownVpnTracker.init();
+ verify(mVpn).setEnableTeardown(false);
+ verify(mVpn).setLockdown(true);
+ verify(mCm).setLegacyLockdownVpnEnabled(true);
+ verify(mVpn).stopVpnRunnerPrivileged();
+ verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+
+ return lockdownVpnTracker;
+ }
+
+ private void callCallbacksForNetworkConnect(NetworkCallback callback, Network network,
+ NetworkCapabilities nc, LinkProperties lp, boolean blocked) {
+ callback.onAvailable(network);
+ callback.onCapabilitiesChanged(network, nc);
+ callback.onLinkPropertiesChanged(network, lp);
+ callback.onBlockedStatusChanged(network, blocked);
+ }
+
+ private void callCallbacksForNetworkConnect(NetworkCallback callback, Network network) {
+ callCallbacksForNetworkConnect(
+ callback, network, TEST_CELL_NC, TEST_CELL_LP, true /* blocked */);
+ }
+
+ private boolean isExpectedNotification(Notification notification, int titleRes, int iconRes) {
+ if (!NOTIFICATION_CHANNEL_VPN.equals(notification.getChannelId())) {
+ return false;
+ }
+ final CharSequence expectedTitle = mContext.getString(titleRes);
+ final CharSequence actualTitle = notification.extras.getCharSequence(
+ Notification.EXTRA_TITLE);
+ if (!TextUtils.equals(expectedTitle, actualTitle)) {
+ return false;
+ }
+ return notification.getSmallIcon().getResId() == iconRes;
+ }
+
+ @Test
+ public void testShutdown() {
+ final LockdownVpnTracker lockdownVpnTracker = initAndVerifyLockdownVpnTracker();
+ final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+ final NetworkCallback vpnCallback = getVpnNetworkCallback();
+ clearInvocations(mVpn, mCm, mNotificationManager);
+
+ lockdownVpnTracker.shutdown();
+ verify(mVpn).stopVpnRunnerPrivileged();
+ verify(mVpn).setLockdown(false);
+ verify(mCm).setLegacyLockdownVpnEnabled(false);
+ verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+ verify(mVpn).setEnableTeardown(true);
+ verify(mCm).unregisterNetworkCallback(defaultCallback);
+ verify(mCm).unregisterNetworkCallback(vpnCallback);
+ }
+
+ @Test
+ public void testDefaultNetworkConnected() {
+ initAndVerifyLockdownVpnTracker();
+ final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+ clearInvocations(mVpn, mCm, mNotificationManager);
+
+ // mNetwork connected and available.
+ callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+
+ // Vpn is starting
+ verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork, TEST_CELL_LP);
+ verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+ argThat(notification -> isExpectedNotification(notification,
+ R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected)));
+ }
+
+ private void doTestDefaultLpChanged(LinkProperties startingLp, LinkProperties newLp) {
+ initAndVerifyLockdownVpnTracker();
+ final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+ callCallbacksForNetworkConnect(
+ defaultCallback, mNetwork, TEST_CELL_NC, startingLp, true /* blocked */);
+ clearInvocations(mVpn, mCm, mNotificationManager);
+
+ // LockdownVpnTracker#handleStateChangedLocked() is not called on the same network even if
+ // the LinkProperties change.
+ defaultCallback.onLinkPropertiesChanged(mNetwork, newLp);
+
+ // Ideally the VPN should start if it hasn't already, but it doesn't because nothing calls
+ // LockdownVpnTracker#handleStateChangedLocked. This is a bug.
+ // TODO: consider fixing this.
+ verify(mVpn, never()).stopVpnRunnerPrivileged();
+ verify(mVpn, never()).startLegacyVpnPrivileged(any(), any(), any());
+ verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+ }
+
+ @Test
+ public void testDefaultLPChanged_V4AddLinkAddressV4() {
+ final LinkProperties lp = new LinkProperties(TEST_CELL_LP);
+ lp.setInterfaceName("rmnet0");
+ lp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+ doTestDefaultLpChanged(TEST_CELL_LP, lp);
+ }
+
+ @Test
+ public void testDefaultLPChanged_V4AddLinkAddressV6() {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("rmnet0");
+ lp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+ final LinkProperties newLp = new LinkProperties(lp);
+ newLp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+ doTestDefaultLpChanged(lp, newLp);
+ }
+
+ @Test
+ public void testDefaultLPChanged_V6AddLinkAddressV4() {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("rmnet0");
+ lp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+ final LinkProperties newLp = new LinkProperties(lp);
+ newLp.addLinkAddress(new LinkAddress("192.0.2.3/25"));
+ doTestDefaultLpChanged(lp, newLp);
+ }
+
+ @Test
+ public void testDefaultLPChanged_AddLinkAddressV4() {
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("rmnet0");
+ doTestDefaultLpChanged(lp, TEST_CELL_LP);
+ }
+
+ @Test
+ public void testDefaultNetworkChanged() {
+ initAndVerifyLockdownVpnTracker();
+ final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+ final NetworkCallback vpnCallback = getVpnNetworkCallback();
+ callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+ clearInvocations(mVpn, mCm, mNotificationManager);
+
+ // New network and LinkProperties received
+ final NetworkCapabilities wifiNc = new NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build();
+ final LinkProperties wifiLp = new LinkProperties();
+ wifiLp.setInterfaceName("wlan0");
+ callCallbacksForNetworkConnect(
+ defaultCallback, mNetwork2, wifiNc, wifiLp, true /* blocked */);
+
+ // Vpn is restarted.
+ verify(mVpn).stopVpnRunnerPrivileged();
+ verify(mVpn).startLegacyVpnPrivileged(mProfile, mNetwork2, wifiLp);
+ verify(mNotificationManager, never()).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+ verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+ argThat(notification -> isExpectedNotification(notification,
+ R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected)));
+
+ // Vpn is Connected
+ doReturn(true).when(mVpnNetworkInfo).isConnectedOrConnecting();
+ doReturn(true).when(mVpnNetworkInfo).isConnected();
+ vpnCallback.onAvailable(mVpnNetwork);
+ verify(mNotificationManager).notify(any(), eq(SystemMessage.NOTE_VPN_STATUS),
+ argThat(notification -> isExpectedNotification(notification,
+ R.string.vpn_lockdown_connected, R.drawable.vpn_connected)));
+
+ }
+
+ @Test
+ public void testSystemDefaultLost() {
+ initAndVerifyLockdownVpnTracker();
+ final NetworkCallback defaultCallback = getDefaultNetworkCallback();
+ // mNetwork connected
+ callCallbacksForNetworkConnect(defaultCallback, mNetwork);
+ clearInvocations(mVpn, mCm, mNotificationManager);
+
+ defaultCallback.onLost(mNetwork);
+
+ // Vpn is stopped
+ verify(mVpn).stopVpnRunnerPrivileged();
+ verify(mNotificationManager).cancel(any(), eq(SystemMessage.NOTE_VPN_STATUS));
+ }
+}
diff --git a/tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt b/tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt
index 7b68a829e23b..7b68a829e23b 100644
--- a/tests/TrustTests/src/android/trust/test/CanUnlockWithActiveUnlockTest.kt
+++ b/tests/TrustTests/src/android/trust/test/IsActiveUnlockRunningTest.kt