Add unit test coverage for unlock attempts in TrustManagerServiceTest

The downstream effects of an unlock attempt using a pin/password were not
previously tested within the TrustManagerServiceTest. Add these tests in
preparation for further changes to pin/password unlock reporting to
TrustManagerService in b/323086607.

BUG: b/323086607
Test: `atest TrustManagerServiceTest`
Flag: TEST_ONLY
Change-Id: I8ce35a822c807c5e272a5d3169b1bf55499d47e0
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f4b61e7..04db3e8 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -275,6 +275,10 @@
             return KeyStoreAuthorization.getInstance();
         }
 
+        AlarmManager getAlarmManager() {
+            return mContext.getSystemService(AlarmManager.class);
+        }
+
         Looper getLooper() {
             return Looper.myLooper();
         }
@@ -293,7 +297,7 @@
         mLockPatternUtils = injector.getLockPatternUtils();
         mKeyStoreAuthorization = injector.getKeyStoreAuthorization();
         mStrongAuthTracker = new StrongAuthTracker(context, injector.getLooper());
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        mAlarmManager = injector.getAlarmManager();
     }
 
     @Override
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 0532e04..2a67029 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.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;
@@ -65,15 +77,22 @@
 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 +100,19 @@
 
 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 {
 
@@ -115,21 +138,28 @@
     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 +188,9 @@
             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 +209,7 @@
         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 +231,7 @@
         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 +250,11 @@
         }
 
         @Override
+        AlarmManager getAlarmManager() {
+            return mAlarmManager;
+        }
+
+        @Override
         Looper getLooper() {
             return mHandlerThread.getLooper();
         }
@@ -367,12 +407,10 @@
 
     @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
@@ -416,6 +454,169 @@
     }
 
     @Test
+    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
     @RequiresFlagsEnabled(android.security.Flags.FLAG_FIX_UNLOCKED_DEVICE_REQUIRED_KEYS_V2)
     public void testKeystoreWeakUnlockEnabled_whenWeakFingerprintIsSetupAndAllowed()
             throws Exception {
@@ -637,6 +838,20 @@
         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() {