summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Biggers <ebiggers@google.com> 2024-06-20 22:15:28 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2024-06-20 22:15:28 +0000
commitb9153aa958e702fe8b1f1268b55b72399bb194f2 (patch)
tree0440de5441894db5cddd798d614ee040f8716063
parentcf7ffed6d71761d02f8ea18f2657410b9eee286e (diff)
parent1583c6a6b5347e2db5d4ae9d1043be3c0d198ed3 (diff)
Merge changes I78dd3268,I8ce35a82 into main
* changes: system_server: make UnlockedDeviceRequired fix unconditional Add unit test coverage for unlock attempts in TrustManagerServiceTest
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java24
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java92
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java35
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java241
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java5
-rw-r--r--tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt23
-rw-r--r--tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt7
7 files changed, 244 insertions, 183 deletions
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 24aea371c094..ecf4eb4502df 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -17,7 +17,6 @@
package android.security;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -112,29 +111,6 @@ public class AndroidKeyStoreMaintenance {
}
/**
- * Informs Keystore 2.0 about changing user's password
- *
- * @param userId - Android user id of the user
- * @param password - a secret derived from the synthetic password provided by the
- * LockSettingsService
- * @return 0 if successful or a {@code ResponseCode}
- * @hide
- */
- public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
- StrictMode.noteDiskWrite();
- try {
- getService().onUserPasswordChanged(userId, password);
- return 0;
- } catch (ServiceSpecificException e) {
- Log.e(TAG, "onUserPasswordChanged failed", e);
- return e.errorCode;
- } catch (Exception e) {
- Log.e(TAG, "Can not connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- /**
* Tells Keystore that a user's LSKF is being removed, ie the user's lock screen is changing to
* Swipe or None. Keystore uses this notification to delete the user's auth-bound keys.
*
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ac29f85b495c..71576465e035 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -252,9 +252,6 @@ public class LockSettingsService extends ILockSettings.Stub {
private static final String MIGRATED_SP_CE_ONLY = "migrated_all_users_to_sp_and_bound_ce";
private static final String MIGRATED_SP_FULL = "migrated_all_users_to_sp_and_bound_keys";
- private static final boolean FIX_UNLOCKED_DEVICE_REQUIRED_KEYS =
- android.security.Flags.fixUnlockedDeviceRequiredKeysV2();
-
// Duration that LockSettingsService will store the gatekeeper password for. This allows
// multiple biometric enrollments without prompting the user to enter their password via
// ConfirmLockPassword/ConfirmLockPattern multiple times. This needs to be at least the duration
@@ -662,7 +659,6 @@ public class LockSettingsService extends ILockSettings.Stub {
mActivityManager = injector.getActivityManager();
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
@@ -899,13 +895,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- // Notify keystore that a new user was added.
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- AndroidKeyStoreMaintenance.onUserAdded(userHandle);
- }
- } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
+ if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
} else if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
@@ -1089,32 +1079,14 @@ public class LockSettingsService extends ILockSettings.Stub {
// Note: if this migration gets interrupted (e.g. by the device powering off), there
// shouldn't be a problem since this will run again on the next boot, and
// setCeStorageProtection() and initKeystoreSuperKeys(..., true) are idempotent.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundKeysLocked(user.id);
- }
- }
- setBoolean(MIGRATED_SP_FULL, true, 0);
- }
- } else {
- if (getString(MIGRATED_SP_CE_ONLY, null, 0) == null) {
- for (UserInfo user : mUserManager.getAliveUsers()) {
- removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
- synchronized (mSpManager) {
- migrateUserToSpWithBoundCeKeyLocked(user.id);
- }
+ if (!getBoolean(MIGRATED_SP_FULL, false, 0)) {
+ for (UserInfo user : mUserManager.getAliveUsers()) {
+ removeStateForReusedUserIdIfNecessary(user.id, user.serialNumber);
+ synchronized (mSpManager) {
+ migrateUserToSpWithBoundKeysLocked(user.id);
}
- setString(MIGRATED_SP_CE_ONLY, "true", 0);
- }
-
- if (getBoolean(MIGRATED_SP_FULL, false, 0)) {
- // The FIX_UNLOCKED_DEVICE_REQUIRED_KEYS flag was enabled but then got disabled.
- // Ensure the full migration runs again the next time the flag is enabled...
- setBoolean(MIGRATED_SP_FULL, false, 0);
}
+ setBoolean(MIGRATED_SP_FULL, true, 0);
}
mThirdPartyAppsStarted = true;
@@ -1122,30 +1094,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@GuardedBy("mSpManager")
- private void migrateUserToSpWithBoundCeKeyLocked(@UserIdInt int userId) {
- if (isUserSecure(userId)) {
- Slogf.d(TAG, "User %d is secured; no migration needed", userId);
- return;
- }
- long protectorId = getCurrentLskfBasedProtectorId(userId);
- if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
- Slogf.i(TAG, "Migrating unsecured user %d to SP-based credential", userId);
- initializeSyntheticPassword(userId);
- } else {
- Slogf.i(TAG, "Existing unsecured user %d has a synthetic password; re-encrypting CE " +
- "key with it", userId);
- AuthenticationResult result = mSpManager.unlockLskfBasedProtector(
- getGateKeeperService(), protectorId, LockscreenCredential.createNone(), userId,
- null);
- if (result.syntheticPassword == null) {
- Slogf.wtf(TAG, "Failed to unwrap synthetic password for unsecured user %d", userId);
- return;
- }
- setCeStorageProtection(userId, result.syntheticPassword);
- }
- }
-
- @GuardedBy("mSpManager")
private void migrateUserToSpWithBoundKeysLocked(@UserIdInt int userId) {
if (isUserSecure(userId)) {
Slogf.d(TAG, "User %d is secured; no migration needed", userId);
@@ -1454,11 +1402,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
- void setKeystorePassword(byte[] password, int userHandle) {
- AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
- }
-
- @VisibleForTesting /** Note: this method is overridden in unit tests */
void initKeystoreSuperKeys(@UserIdInt int userId, SyntheticPassword sp, boolean allowExisting) {
final byte[] password = sp.deriveKeyStorePassword();
try {
@@ -2195,9 +2138,7 @@ public class LockSettingsService extends ILockSettings.Stub {
return;
}
onSyntheticPasswordUnlocked(userId, result.syntheticPassword);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- unlockKeystore(userId, result.syntheticPassword);
- }
+ unlockKeystore(userId, result.syntheticPassword);
unlockCeStorage(userId, result.syntheticPassword);
}
}
@@ -2503,9 +2444,7 @@ public class LockSettingsService extends ILockSettings.Stub {
// long time, so for now we keep doing it just in case it's ever important. Don't wait
// until initKeystoreSuperKeys() to do this; that can be delayed if the user is being
// created during early boot, and maybe something will use Keystore before then.
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserAdded(userId);
- }
+ AndroidKeyStoreMaintenance.onUserAdded(userId);
synchronized (mUserCreationAndRemovalLock) {
// During early boot, don't actually create the synthetic password yet, but rather
@@ -2931,9 +2870,7 @@ public class LockSettingsService extends ILockSettings.Stub {
LockscreenCredential.createNone(), sp, userId);
setCurrentLskfBasedProtectorId(protectorId, userId);
setCeStorageProtection(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
- }
+ initKeystoreSuperKeys(userId, sp, /* allowExisting= */ false);
onSyntheticPasswordCreated(userId, sp);
Slogf.i(TAG, "Successfully initialized synthetic password for user %d", userId);
return sp;
@@ -3048,9 +2985,6 @@ public class LockSettingsService extends ILockSettings.Stub {
if (!mSpManager.hasSidForUser(userId)) {
mSpManager.newSidForUser(getGateKeeperService(), sp, userId);
mSpManager.verifyChallenge(getGateKeeperService(), sp, 0L, userId);
- if (!FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- setKeystorePassword(sp.deriveKeyStorePassword(), userId);
- }
}
} else {
// Cache all profile password if they use unified challenge. This will later be used to
@@ -3061,11 +2995,7 @@ public class LockSettingsService extends ILockSettings.Stub {
gateKeeperClearSecureUserId(userId);
unlockCeStorage(userId, sp);
unlockKeystore(userId, sp);
- if (FIX_UNLOCKED_DEVICE_REQUIRED_KEYS) {
- AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
- } else {
- setKeystorePassword(null, userId);
- }
+ AndroidKeyStoreMaintenance.onUserLskfRemoved(userId);
removeBiometricsForUser(userId);
}
setCurrentLskfBasedProtectorId(newProtectorId, userId);
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f62c76e1505a..b3c31a9cfb64 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -267,6 +267,10 @@ public class TrustManagerService extends SystemService {
return KeyStoreAuthorization.getInstance();
}
+ AlarmManager getAlarmManager() {
+ return mContext.getSystemService(AlarmManager.class);
+ }
+
Looper getLooper() {
return Looper.myLooper();
}
@@ -285,7 +289,7 @@ public class TrustManagerService extends SystemService {
mLockPatternUtils = injector.getLockPatternUtils();
mKeyStoreAuthorization = injector.getKeyStoreAuthorization();
mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
- mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ mAlarmManager = injector.getAlarmManager();
}
@Override
@@ -845,12 +849,7 @@ public class TrustManagerService extends SystemService {
continue;
}
- final boolean trusted;
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
- } else {
- trusted = aggregateIsTrusted(id);
- }
+ final boolean trusted = getUserTrustStateInner(id) == TrustState.TRUSTED;
boolean showingKeyguard = true;
boolean biometricAuthenticated = false;
boolean currentUserIsUnlocked = false;
@@ -911,19 +910,15 @@ public class TrustManagerService extends SystemService {
private void notifyKeystoreOfDeviceLockState(int userId, boolean isLocked) {
if (isLocked) {
- if (android.security.Flags.fixUnlockedDeviceRequiredKeysV2()) {
- // A profile with unified challenge is unlockable not by its own biometrics and
- // trust agents, but rather by those of the parent user. Therefore, when protecting
- // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
- // biometric SIDs and weak unlock methods, not the profile's.
- int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
- ? resolveProfileParent(userId) : userId;
-
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
- isWeakUnlockMethodEnabled(authUserId));
- } else {
- mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(userId), false);
- }
+ // A profile with unified challenge is unlockable not by its own biometrics and
+ // trust agents, but rather by those of the parent user. Therefore, when protecting
+ // the profile's UnlockedDeviceRequired keys, we must use the parent's list of
+ // biometric SIDs and weak unlock methods, not the profile's.
+ int authUserId = mLockPatternUtils.isProfileWithUnifiedChallenge(userId)
+ ? resolveProfileParent(userId) : userId;
+
+ mKeyStoreAuthorization.onDeviceLocked(userId, getBiometricSids(authUserId),
+ isWeakUnlockMethodEnabled(authUserId));
} else {
// Notify Keystore that the device is now unlocked for the user. Note that for unlocks
// with LSKF, this is redundant with the call from LockSettingsService which provides
diff --git a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
index 0532e04257d4..7aec42b7eceb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/trust/TrustManagerServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.trust;
+import static android.service.trust.TrustAgentService.FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE;
+
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
@@ -26,12 +28,22 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+
+import static java.util.Collections.singleton;
+
import android.Manifest;
import android.annotation.Nullable;
import android.app.ActivityManager;
+import android.app.AlarmManager;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
@@ -60,20 +72,24 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
import android.security.KeyStoreAuthorization;
+import android.service.trust.GrantTrustResult;
+import android.service.trust.ITrustAgentService;
+import android.service.trust.ITrustAgentServiceCallback;
import android.service.trust.TrustAgentService;
import android.testing.TestableContext;
+import android.util.Log;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
import androidx.test.core.app.ApplicationProvider;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.StrongAuthFlags;
+import com.android.internal.widget.LockSettingsInternal;
import com.android.modules.utils.testing.ExtendedMockitoRule;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -81,15 +97,19 @@ import com.android.server.SystemServiceManager;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
+import org.mockito.Mockito;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
public class TrustManagerServiceTest {
@@ -101,9 +121,6 @@ public class TrustManagerServiceTest {
.build();
@Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- @Rule
public final MockContext mMockContext = new MockContext(
ApplicationProvider.getApplicationContext());
@@ -115,21 +132,28 @@ public class TrustManagerServiceTest {
private static final int PROFILE_USER_ID = 70;
private static final long[] PARENT_BIOMETRIC_SIDS = new long[] { 600L, 601L };
private static final long[] PROFILE_BIOMETRIC_SIDS = new long[] { 700L, 701L };
+ private static final long RENEWABLE_TRUST_DURATION = 10000L;
+ private static final String GRANT_TRUST_MESSAGE = "granted";
+ private static final String TAG = "TrustManagerServiceTest";
private final ArrayList<ResolveInfo> mTrustAgentResolveInfoList = new ArrayList<>();
private final ArrayList<ComponentName> mKnownTrustAgents = new ArrayList<>();
private final ArrayList<ComponentName> mEnabledTrustAgents = new ArrayList<>();
+ private final Map<ComponentName, ITrustAgentService.Stub> mMockTrustAgents = new HashMap<>();
private @Mock ActivityManager mActivityManager;
+ private @Mock AlarmManager mAlarmManager;
private @Mock BiometricManager mBiometricManager;
private @Mock DevicePolicyManager mDevicePolicyManager;
private @Mock FaceManager mFaceManager;
private @Mock FingerprintManager mFingerprintManager;
private @Mock KeyStoreAuthorization mKeyStoreAuthorization;
private @Mock LockPatternUtils mLockPatternUtils;
+ private @Mock LockSettingsInternal mLockSettingsInternal;
private @Mock PackageManager mPackageManager;
private @Mock UserManager mUserManager;
private @Mock IWindowManager mWindowManager;
+ private @Mock ITrustListener mTrustListener;
private HandlerThread mHandlerThread;
private TrustManagerService mService;
@@ -158,6 +182,9 @@ public class TrustManagerServiceTest {
return null;
}).when(mLockPatternUtils).setEnabledTrustAgents(any(), eq(TEST_USER_ID));
+ LocalServices.removeServiceForTest(LockSettingsInternal.class);
+ LocalServices.addService(LockSettingsInternal.class, mLockSettingsInternal);
+
ArgumentMatcher<Intent> trustAgentIntentMatcher = new ArgumentMatcher<Intent>() {
@Override
public boolean matches(Intent argument) {
@@ -176,6 +203,7 @@ public class TrustManagerServiceTest {
when(mWindowManager.isKeyguardLocked()).thenReturn(true);
mMockContext.addMockSystemService(ActivityManager.class, mActivityManager);
+ mMockContext.addMockSystemService(AlarmManager.class, mAlarmManager);
mMockContext.addMockSystemService(BiometricManager.class, mBiometricManager);
mMockContext.addMockSystemService(FaceManager.class, mFaceManager);
mMockContext.addMockSystemService(FingerprintManager.class, mFingerprintManager);
@@ -197,6 +225,7 @@ public class TrustManagerServiceTest {
verify(() -> ServiceManager.addService(eq(Context.TRUST_SERVICE),
binderArgumentCaptor.capture(), anyBoolean(), anyInt()));
mTrustManager = ITrustManager.Stub.asInterface(binderArgumentCaptor.getValue());
+ mTrustManager.registerTrustListener(mTrustListener);
}
private class MockInjector extends TrustManagerService.Injector {
@@ -215,6 +244,11 @@ public class TrustManagerServiceTest {
}
@Override
+ AlarmManager getAlarmManager() {
+ return mAlarmManager;
+ }
+
+ @Override
Looper getLooper() {
return mHandlerThread.getLooper();
}
@@ -367,12 +401,10 @@ public class TrustManagerServiceTest {
@Test
public void reportEnabledTrustAgentsChangedInformsListener() throws RemoteException {
- final ITrustListener trustListener = mock(ITrustListener.class);
- mTrustManager.registerTrustListener(trustListener);
mService.waitForIdle();
mTrustManager.reportEnabledTrustAgentsChanged(TEST_USER_ID);
mService.waitForIdle();
- verify(trustListener).onEnabledTrustAgentsChanged(TEST_USER_ID);
+ verify(mTrustListener).onEnabledTrustAgentsChanged(TEST_USER_ID);
}
// Tests that when the device is locked for a managed profile with a *unified* challenge, the
@@ -380,7 +412,6 @@ public class TrustManagerServiceTest {
// user, not the profile. This matches the authentication that is needed to unlock the device
// for the profile again.
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testLockDeviceForManagedProfileWithUnifiedChallenge_usesParentBiometricSids()
throws Exception {
setupMocksForProfile(/* unifiedChallenge= */ true);
@@ -416,7 +447,169 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
+ public void testSuccessfulUnlock_bindsTrustAgent() throws Exception {
+ when(mUserManager.getAliveUsers())
+ .thenReturn(List.of(new UserInfo(TEST_USER_ID, "test", UserInfo.FLAG_FULL)));
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ assertThat(getCallback(trustAgentService)).isNotNull();
+ }
+
+ @Test
+ public void testSuccessfulUnlock_notifiesTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService).onUnlockAttempt(/* successful= */ true);
+ }
+
+ @Test
+ public void testSuccessfulUnlock_notifiesTrustListenerOfChangeInManagedTrust()
+ throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ mService.waitForIdle();
+ Mockito.reset(mTrustListener);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(mTrustListener).onTrustManagedChanged(false, TEST_USER_ID);
+ }
+
+ @Test
+ @Ignore("TODO: b/340891566 - Trustagent always refreshes trustable timer for user 0 on unlock")
+ public void testSuccessfulUnlock_refreshesTrustableTimers() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgent =
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ setUpRenewableTrust(trustAgent);
+
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ // Idle and hard timeout alarms for first renewable trust granted
+ // Idle timeout alarm refresh for second renewable trust granted
+ // Idle and hard timeout alarms refresh for last report
+ verify(mAlarmManager, times(3))
+ .setExact(
+ eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(),
+ anyString(),
+ any(AlarmManager.OnAlarmListener.class),
+ any(Handler.class));
+ }
+
+ @Test
+ public void testFailedUnlock_doesNotBindTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(
+ trustAgentName, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService, never()).setCallback(any());
+ }
+
+ @Test
+ public void testFailedUnlock_notifiesTrustAgent() throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ ITrustAgentService trustAgentService =
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(trustAgentService).onUnlockAttempt(/* successful= */ false);
+ }
+
+ @Test
+ public void testFailedUnlock_doesNotNotifyTrustListenerOfChangeInManagedTrust()
+ throws Exception {
+ ComponentName trustAgentName =
+ ComponentName.unflattenFromString("com.android/.SystemTrustAgent");
+ setUpTrustAgentWithStrongAuthRequired(trustAgentName, STRONG_AUTH_NOT_REQUIRED);
+ Mockito.reset(mTrustListener);
+
+ attemptFailedUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+
+ verify(mTrustListener, never()).onTrustManagedChanged(anyBoolean(), anyInt());
+ }
+
+ private void setUpRenewableTrust(ITrustAgentService trustAgent) throws RemoteException {
+ ITrustAgentServiceCallback callback = getCallback(trustAgent);
+ callback.setManagingTrust(true);
+ mService.waitForIdle();
+ attemptSuccessfulUnlock(TEST_USER_ID);
+ mService.waitForIdle();
+ when(mWindowManager.isKeyguardLocked()).thenReturn(false);
+ grantRenewableTrust(callback);
+ }
+
+ private ITrustAgentService setUpTrustAgentWithStrongAuthRequired(
+ ComponentName agentName, @StrongAuthFlags int strongAuthFlags) throws Exception {
+ doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(TEST_USER_ID);
+ addTrustAgent(agentName, true);
+ mLockPatternUtils.setKnownTrustAgents(singleton(agentName), TEST_USER_ID);
+ mLockPatternUtils.setEnabledTrustAgents(singleton(agentName), TEST_USER_ID);
+ when(mUserManager.isUserUnlockingOrUnlocked(TEST_USER_ID)).thenReturn(true);
+ setupStrongAuthTracker(strongAuthFlags, false);
+ mService.waitForIdle();
+ return getOrCreateMockTrustAgent(agentName);
+ }
+
+ private void attemptSuccessfulUnlock(int userId) throws RemoteException {
+ mTrustManager.reportUnlockAttempt(/* successful= */ true, userId);
+ }
+
+ private void attemptFailedUnlock(int userId) throws RemoteException {
+ mTrustManager.reportUnlockAttempt(/* successful= */ false, userId);
+ }
+
+ private void grantRenewableTrust(ITrustAgentServiceCallback callback) throws RemoteException {
+ Log.i(TAG, "Granting trust");
+ AndroidFuture<GrantTrustResult> future = new AndroidFuture<>();
+ callback.grantTrust(
+ GRANT_TRUST_MESSAGE,
+ RENEWABLE_TRUST_DURATION,
+ FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE,
+ future);
+ mService.waitForIdle();
+ }
+
+ /**
+ * Retrieve the ITrustAgentServiceCallback attached to a TrustAgentService after it has been
+ * bound to by the TrustManagerService. Will fail if no binding was established.
+ */
+ private ITrustAgentServiceCallback getCallback(ITrustAgentService trustAgentService)
+ throws RemoteException {
+ ArgumentCaptor<ITrustAgentServiceCallback> callbackCaptor =
+ ArgumentCaptor.forClass(ITrustAgentServiceCallback.class);
+ verify(trustAgentService).setCallback(callbackCaptor.capture());
+ return callbackCaptor.getValue();
+ }
+
+ @Test
public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -425,7 +618,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenWeakFaceIsSetupAndAllowed() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -433,7 +625,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFingerprintIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -442,7 +633,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockEnabled_whenConvenienceFaceIsSetupAndAllowed()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -451,7 +641,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenStrongAuthRequired() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN, true);
setupFace(SensorProperties.STRENGTH_WEAK);
@@ -459,7 +648,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNonStrongBiometricNotAllowed() throws Exception {
setupStrongAuthTracker(StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED,
/* isNonStrongBiometricAllowed= */ false);
@@ -468,7 +656,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFingerprintSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -477,7 +664,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceSensorIsPresentButNotEnrolled()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -486,7 +672,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void
testKeystoreWeakUnlockDisabled_whenWeakFingerprintIsSetupButForbiddenByDevicePolicy()
throws Exception {
@@ -498,7 +683,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenWeakFaceIsSetupButForbiddenByDevicePolicy()
throws Exception {
setupStrongAuthTrackerToAllowEverything();
@@ -509,7 +693,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFingerprintIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFingerprint(SensorProperties.STRENGTH_STRONG);
@@ -517,7 +700,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenOnlyStrongFaceIsSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
setupFace(SensorProperties.STRENGTH_STRONG);
@@ -525,7 +707,6 @@ public class TrustManagerServiceTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
public void testKeystoreWeakUnlockDisabled_whenNoBiometricsAreSetup() throws Exception {
setupStrongAuthTrackerToAllowEverything();
verifyWeakUnlockDisabled();
@@ -637,6 +818,20 @@ public class TrustManagerServiceTest {
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.serviceInfo = serviceInfo;
mTrustAgentResolveInfoList.add(resolveInfo);
+ ITrustAgentService.Stub mockService = getOrCreateMockTrustAgent(agentComponentName);
+ mMockContext.addMockService(agentComponentName, mockService);
+ mMockTrustAgents.put(agentComponentName, mockService);
+ }
+
+ private ITrustAgentService.Stub getOrCreateMockTrustAgent(ComponentName agentComponentName) {
+ return mMockTrustAgents.computeIfAbsent(
+ agentComponentName,
+ (componentName) -> {
+ ITrustAgentService.Stub mockTrustAgent = mock(ITrustAgentService.Stub.class);
+ when(mockTrustAgent.queryLocalInterface(anyString()))
+ .thenReturn(mockTrustAgent);
+ return mockTrustAgent;
+ });
}
private void bootService() {
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index f9077c4ae602..93fc071a5bb7 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -196,11 +196,6 @@ public class LockSettingsServiceTestable extends LockSettingsService {
}
@Override
- void setKeystorePassword(byte[] password, int userHandle) {
-
- }
-
- @Override
void initKeystoreSuperKeys(int userId, SyntheticPassword sp, boolean allowExisting) {
}
diff --git a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
index d0e56268a27d..0c3c7e2af6f2 100644
--- a/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
+++ b/tests/TrustTests/src/android/trust/test/GrantAndRevokeTrustTest.kt
@@ -17,9 +17,6 @@
package android.trust.test
import android.content.pm.PackageManager
-import android.platform.test.annotations.RequiresFlagsDisabled
-import android.platform.test.annotations.RequiresFlagsEnabled
-import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.service.trust.GrantTrustResult
import android.trust.BaseTrustAgentService
import android.trust.TrustTestActivity
@@ -58,7 +55,6 @@ class GrantAndRevokeTrustTest {
.around(ScreenLockRule())
.around(lockStateTrackingRule)
.around(trustAgentRule)
- .around(DeviceFlagsValueProvider.createCheckFlagsRule())
@Before
fun manageTrust() {
@@ -93,7 +89,6 @@ class GrantAndRevokeTrustTest {
}
@Test
- @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
fun grantCannotActivelyUnlockDevice() {
// On automotive, trust agents can actively unlock the device.
assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
@@ -120,24 +115,6 @@ class GrantAndRevokeTrustTest {
}
@Test
- @RequiresFlagsDisabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
- fun grantCouldCauseWrongDeviceLockedStateDueToBug() {
- // On automotive, trust agents can actively unlock the device.
- assumeFalse(packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE))
-
- // Verify that b/296464083 exists. That is, when the device is locked
- // and a trust agent grants trust, the deviceLocked state incorrectly
- // becomes false even though the device correctly remains locked.
- uiDevice.sleep()
- lockStateTrackingRule.assertLocked()
- trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 10000, 0) {}
- uiDevice.wakeUp()
- uiDevice.sleep()
- await()
- lockStateTrackingRule.assertUnlockedButNotReally()
- }
-
- @Test
fun grantDoesNotCallBack() {
val callback = mock<(GrantTrustResult) -> Unit>()
trustAgentRule.agent.grantTrust(GRANT_MESSAGE, 0, 0, callback)
diff --git a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
index 01218099f34c..80d79478c898 100644
--- a/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
+++ b/tests/TrustTests/src/android/trust/test/lib/LockStateTrackingRule.kt
@@ -64,13 +64,6 @@ class LockStateTrackingRule : TestRule {
wait("not trusted") { trustState.trusted == false }
}
- // TODO(b/299298338) remove this when removing FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2
- fun assertUnlockedButNotReally() {
- wait("device unlocked") { !keyguardManager.isDeviceLocked }
- wait("not trusted") { trustState.trusted == false }
- wait("keyguard locked") { windowManager.isKeyguardLocked }
- }
-
fun assertUnlockedAndTrusted() {
wait("device unlocked") { !keyguardManager.isDeviceLocked }
wait("trusted") { trustState.trusted == true }