Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bcb85a9a authored by Kevin Chyn's avatar Kevin Chyn
Browse files

3/n: Add and use Fingerprint AIDL stop/start user clients

Bug: 181984005
Test: atest com.android.server.biometrics
Test: atest CtsBiometricsTestCases
Change-Id: If7dd9342629471419498f2d502bddfe031ad11b1
parent 302b4085
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -25,18 +25,27 @@ import android.os.IBinder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.BiometricsProto;

public abstract class StartUserClient<T>  extends HalClientMonitor<T> {
/**
 * Abstract class for starting a new user.
 * @param <T> Interface to request a new user.
 * @param <U> Newly created user object.
 */
public abstract class StartUserClient<T, U>  extends HalClientMonitor<T> {

    public interface UserStartedCallback {
        void onUserStarted(int newUserId);
    /**
     * Invoked when the new user is started.
     * @param <U> New user object.
     */
    public interface UserStartedCallback<U> {
        void onUserStarted(int newUserId, U newUser);
    }

    @NonNull @VisibleForTesting
    protected final UserStartedCallback mUserStartedCallback;
    protected final UserStartedCallback<U> mUserStartedCallback;

    public StartUserClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
            @Nullable IBinder token, int userId, int sensorId,
            @NonNull UserStartedCallback callback) {
            @NonNull UserStartedCallback<U> callback) {
        super(context, lazyDaemon, token, null /* listener */, userId, context.getOpPackageName(),
                0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
                BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
+10 −1
Original line number Diff line number Diff line
@@ -25,6 +25,10 @@ import android.os.IBinder;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.biometrics.BiometricsProto;

/**
 * Abstract class for stopping a user.
 * @param <T> Interface for stopping the user.
 */
public abstract class StopUserClient<T> extends HalClientMonitor<T> {

    public interface UserStoppedCallback {
@@ -32,7 +36,12 @@ public abstract class StopUserClient<T> extends HalClientMonitor<T> {
    }

    @NonNull @VisibleForTesting
    protected final UserStoppedCallback mUserStoppedCallback;
    private final UserStoppedCallback mUserStoppedCallback;

    public void onUserStopped() {
        mUserStoppedCallback.onUserStopped();
        getCallback().onClientFinished(this, true /* success */);
    }

    public StopUserClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
            @Nullable IBinder token, int userId, int sensorId,
+1 −1
Original line number Diff line number Diff line
@@ -45,7 +45,7 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {

    public interface UserSwitchCallback {
        @NonNull StopUserClient<?> getStopUserClient(int userId);
        @NonNull StartUserClient<?> getStartUserClient(int newUserId);
        @NonNull StartUserClient<?, ?> getStartUserClient(int newUserId);
    }

    @NonNull private final CurrentUserRetriever mCurrentUserRetriever;
+2 −1
Original line number Diff line number Diff line
@@ -135,7 +135,8 @@ public class TestHal extends IFace.Stub {

            @Override
            public void close(int cookie) throws RemoteException {
                cb.onStateChanged(cookie, SessionState.CLOSED);
                Slog.w(TAG, "close, cookie: " + cookie);
                cb.onSessionClosed();
            }
        };
    }
+74 −245
Original line number Diff line number Diff line
@@ -82,7 +82,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    @NonNull private final String mHalInstanceName;
    @NonNull @VisibleForTesting
    final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
    @NonNull private final HalClientMonitor.LazyDaemon<IFingerprint> mLazyDaemon;
    @NonNull private final Handler mHandler;
    @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
    @NonNull private final ActivityTaskManager mActivityTaskManager;
@@ -131,7 +130,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
        mContext = context;
        mHalInstanceName = halInstanceName;
        mSensors = new SparseArray<>();
        mLazyDaemon = this::getHalInstance;
        mHandler = new Handler(Looper.getMainLooper());
        mLockoutResetDispatcher = lockoutResetDispatcher;
        mActivityTaskManager = ActivityTaskManager.getInstance();
@@ -169,7 +167,8 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    }

    @Nullable
    private synchronized IFingerprint getHalInstance() {
    @VisibleForTesting
    synchronized IFingerprint getHalInstance() {
        if (mTestHalEnabled) {
            // Enabling the test HAL for a single sensor in a multi-sensor HAL currently enables
            // the test HAL for all sensors under that HAL. This can be updated in the future if
@@ -224,21 +223,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
        mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
    }

    private void createNewSessionWithoutHandler(@NonNull IFingerprint daemon, int sensorId,
            int userId) throws RemoteException {
        // Note that per IFingerprint createSession contract, this method will block until all
        // existing operations are canceled/finished. However, also note that this is fine, since
        // this method "withoutHandler" means it should only ever be invoked from the worker thread,
        // so callers will never be blocked.
        mSensors.get(sensorId).createNewSession(daemon, sensorId, userId);

        if (FingerprintUtils.getInstance(sensorId).isInvalidationInProgress(mContext, userId)) {
            Slog.w(getTag(), "Scheduling unfinished invalidation request for sensor: " + sensorId
                    + ", user: " + userId);
            scheduleInvalidationRequest(sensorId, userId);
        }
    }

    @Override
    public boolean containsSensor(int sensorId) {
        return mSensors.contains(sensorId);
@@ -275,32 +259,16 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi

    private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during loadAuthenticatorIds, sensorId: " + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintGetAuthenticatorIdClient client =
                    new FingerprintGetAuthenticatorIdClient(mContext,
                            mSensors.get(sensorId).getLazySession(), userId,
                            mContext.getOpPackageName(), sensorId,
                            mSensors.get(sensorId).getAuthenticatorIds());
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling loadAuthenticatorId"
                        + ", sensorId: " + sensorId
                        + ", userId: " + userId, e);
            }
        });
    }

    private void scheduleInvalidationRequest(int sensorId, int userId) {
    void scheduleInvalidationRequest(int sensorId, int userId) {
        mHandler.post(() -> {
            final InvalidationRequesterClient<Fingerprint> client =
                    new InvalidationRequesterClient<>(mContext, userId, sensorId,
@@ -312,25 +280,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    @Override
    public void scheduleResetLockout(int sensorId, int userId, @Nullable byte[] hardwareAuthToken) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during resetLockout, sensorId: " + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient(
                    mContext, mSensors.get(sensorId).getLazySession(), userId,
                    mContext.getOpPackageName(), sensorId, hardwareAuthToken,
                    mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling resetLockout", e);
            }
        });
    }

@@ -338,26 +292,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
            @NonNull IFingerprintServiceReceiver receiver, String opPackageName) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during generateChallenge, sensorId: " + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintGenerateChallengeClient client =
                    new FingerprintGenerateChallengeClient(mContext,
                            mSensors.get(sensorId).getLazySession(), token,
                            new ClientMonitorCallbackConverter(receiver), opPackageName,
                            sensorId);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling generateChallenge", e);
            }
        });
    }

@@ -365,25 +305,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
            @NonNull String opPackageName, long challenge) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during revokeChallenge, sensorId: " + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintRevokeChallengeClient client =
                    new FingerprintRevokeChallengeClient(mContext,
                            mSensors.get(sensorId).getLazySession(), token,
                            opPackageName, sensorId, challenge);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling revokeChallenge", e);
            }
        });
    }

@@ -392,20 +318,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
            int userId, @NonNull IFingerprintServiceReceiver receiver,
            @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during enroll, sensorId: " + sensorId);
                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
                // this operation. We should not send the callback yet, since the scheduler may
                // be processing something else.
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
                    .maxEnrollmentsPerUser;
            final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
@@ -423,9 +335,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
                    }
                }
            });
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling enroll", e);
            }
        });
    }

@@ -439,29 +348,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
            @NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
            int statsClient) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during finger detect, sensorId: " + sensorId);
                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
                // this operation. We should not send the callback yet, since the scheduler may
                // be processing something else.
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
            final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
                    mSensors.get(sensorId).getLazySession(), token, callback, userId,
                    opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric,
                    statsClient);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling finger detect", e);
            }
        });
    }

@@ -471,20 +363,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
            @NonNull String opPackageName, boolean restricted, int statsClient,
            boolean allowBackgroundAuthentication) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during authenticate, sensorId: " + sensorId);
                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
                // this operation. We should not send the callback yet, since the scheduler may
                // be processing something else.
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
            final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
                    mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
@@ -493,9 +371,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
                    mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
                    mUdfpsOverlayController, allowBackgroundAuthentication);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
            }
        });
    }

@@ -535,29 +410,12 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
            int[] fingerprintIds, int userId, @NonNull IFingerprintServiceReceiver receiver,
            @NonNull String opPackageName) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during remove, sensorId: " + sensorId);
                // If this happens, we need to send HW_UNAVAILABLE after the scheduler gets to
                // this operation. We should not send the callback yet, since the scheduler may
                // be processing something else.
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
                    mSensors.get(sensorId).getLazySession(), token,
                    new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
                    opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
                    mSensors.get(sensorId).getAuthenticatorIds());
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling remove", e);
            }
        });
    }

@@ -565,17 +423,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    public void scheduleInternalCleanup(int sensorId, int userId,
            @Nullable BaseClientMonitor.Callback callback) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during internal cleanup, sensorId: " + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final List<Fingerprint> enrolledList = getEnrolledFingerprints(sensorId, userId);
            final FingerprintInternalCleanupClient client =
                    new FingerprintInternalCleanupClient(mContext,
@@ -584,9 +431,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
                            FingerprintUtils.getInstance(sensorId),
                            mSensors.get(sensorId).getAuthenticatorIds());
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
            }
        });
    }

@@ -611,26 +455,11 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
    public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
            @NonNull IInvalidationCallback callback) {
        mHandler.post(() -> {
            final IFingerprint daemon = getHalInstance();
            if (daemon == null) {
                Slog.e(getTag(), "Null daemon during scheduleInvalidateAuthenticatorId: "
                        + sensorId);
                return;
            }

            try {
                if (!mSensors.get(sensorId).hasSessionForUser(userId)) {
                    createNewSessionWithoutHandler(daemon, sensorId, userId);
                }

            final FingerprintInvalidationClient client =
                    new FingerprintInvalidationClient(mContext,
                            mSensors.get(sensorId).getLazySession(), userId, sensorId,
                            mSensors.get(sensorId).getAuthenticatorIds(), callback);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception", e);
            }
        });
    }

Loading