diff options
| author | 2024-06-20 22:15:28 +0000 | |
|---|---|---|
| committer | 2024-06-20 22:15:28 +0000 | |
| commit | b9153aa958e702fe8b1f1268b55b72399bb194f2 (patch) | |
| tree | 0440de5441894db5cddd798d614ee040f8716063 | |
| parent | cf7ffed6d71761d02f8ea18f2657410b9eee286e (diff) | |
| parent | 1583c6a6b5347e2db5d4ae9d1043be3c0d198ed3 (diff) | |
Merge changes I78dd3268,I8ce35a82 into main
* changes:
system_server: make UnlockedDeviceRequired fix unconditional
Add unit test coverage for unlock attempts in TrustManagerServiceTest
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 } |