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

Commit 0b296ebd authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge changes from topic "biometric-stopstart" into sc-dev

* changes:
  6/n: Update UserAwareBiometricScheduler
  5/n: Update some biometric logcats
  4/n: Add and use Face AIDL start/stop user clients
  3/n: Add and use Fingerprint AIDL stop/start user clients
parents d2f65cf1 5309214d
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,
+24 −7
Original line number Diff line number Diff line
@@ -45,13 +45,15 @@ 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;
    @NonNull private final UserSwitchCallback mUserSwitchCallback;
    @NonNull @VisibleForTesting final ClientFinishedCallback mClientFinishedCallback;

    @Nullable private StopUserClient<?> mStopUserClient;

    @VisibleForTesting
    class ClientFinishedCallback implements BaseClientMonitor.Callback {
        @Override
@@ -108,16 +110,31 @@ public class UserAwareBiometricScheduler extends BiometricScheduler {
        if (nextUserId == currentUserId) {
            super.startNextOperationIfIdle();
        } else if (currentUserId == UserHandle.USER_NULL) {
            Slog.d(getTag(), "User switch required, current user null, next: " + nextUserId);
            final BaseClientMonitor startClient =
                    mUserSwitchCallback.getStartUserClient(nextUserId);
            Slog.d(getTag(), "[Starting User] " + startClient);
            startClient.start(mClientFinishedCallback);
        } else {
            final BaseClientMonitor stopClient = mUserSwitchCallback
            if (mStopUserClient != null) {
                Slog.d(getTag(), "[Waiting for StopUser] " + mStopUserClient);
            } else {
                mStopUserClient = mUserSwitchCallback
                        .getStopUserClient(currentUserId);
            Slog.d(getTag(), "User switch required, current: " + currentUserId
                    + ", next: " + nextUserId + ". " + stopClient);
            stopClient.start(mClientFinishedCallback);
                Slog.d(getTag(), "[Stopping User] current: " + currentUserId
                        + ", next: " + nextUserId + ". " + mStopUserClient);
                mStopUserClient.start(mClientFinishedCallback);
            }
        }
    }

    public void onUserStopped() {
        if (mStopUserClient == null) {
            Slog.e(getTag(), "Unexpected onUserStopped");
            return;
        }

        Slog.d(getTag(), "[OnUserStopped]: " + mStopUserClient);
        mStopUserClient.onUserStopped();
        mStopUserClient = null;
    }
}
+0 −3
Original line number Diff line number Diff line
@@ -502,9 +502,6 @@ public class FaceService extends SystemService implements BiometricServiceCallba
                return false;
            }

            final boolean enrolled = provider.getEnrolledFaces(sensorId, userId).size() > 0;
            Slog.d(TAG, "hasEnrolledFaces, sensor: " + sensorId + ", enrolled: " + enrolled);

            return provider.getEnrolledFaces(sensorId, userId).size() > 0;
        }

+64 −223
Original line number Diff line number Diff line
@@ -78,7 +78,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    @NonNull private final String mHalInstanceName;
    @NonNull @VisibleForTesting
    final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
    @NonNull private final HalClientMonitor.LazyDaemon<IFace> mLazyDaemon;
    @NonNull private final Handler mHandler;
    @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
    @NonNull private final UsageStats mUsageStats;
@@ -126,7 +125,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
        mContext = context;
        mHalInstanceName = halInstanceName;
        mSensors = new SparseArray<>();
        mLazyDaemon = this::getHalInstance;
        mHandler = new Handler(Looper.getMainLooper());
        mUsageStats = new UsageStats(context);
        mLockoutResetDispatcher = lockoutResetDispatcher;
@@ -163,7 +161,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    }

    @Nullable
    private synchronized IFace getHalInstance() {
    @VisibleForTesting
    synchronized IFace getHalInstance() {
        if (mTestHalEnabled) {
            return new TestHal();
        }
@@ -214,22 +213,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
        mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client, callback);
    }

    private void createNewSessionWithoutHandler(@NonNull IFace daemon, int sensorId,
            int userId) throws RemoteException {
        // Note that per IFace 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 (FaceUtils.getInstance(sensorId).isInvalidationInProgress(mContext, userId)) {
            Slog.w(getTag(), "Scheduling unfinished invalidation request for sensor: " + sensorId
                    + ", user: " + userId);
            scheduleInvalidationRequest(sensorId, userId);
        }
    }


    private void scheduleLoadAuthenticatorIds(int sensorId) {
        for (UserInfo user : UserManager.get(mContext).getAliveUsers()) {
            scheduleLoadAuthenticatorIdsForUser(sensorId, user.id);
@@ -238,32 +221,16 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {

    private void scheduleLoadAuthenticatorIdsForUser(int sensorId, int userId) {
        mHandler.post(() -> {
            final IFace 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 FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
                    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<Face> client =
                    new InvalidationRequesterClient<>(mContext, userId, sensorId,
@@ -303,25 +270,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    public void scheduleInvalidateAuthenticatorId(int sensorId, int userId,
            @NonNull IInvalidationCallback callback) {
        mHandler.post(() -> {
            final IFace 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 FaceInvalidationClient client = new FaceInvalidationClient(mContext,
                    mSensors.get(sensorId).getLazySession(), userId, sensorId,
                    mSensors.get(sensorId).getAuthenticatorIds(), callback);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception", e);
            }
        });
    }

@@ -344,25 +296,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token,
            @NonNull IFaceServiceReceiver receiver, String opPackageName) {
        mHandler.post(() -> {
            final IFace 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 FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(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);
            }
        });
    }

@@ -370,25 +307,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token,
            @NonNull String opPackageName, long challenge) {
        mHandler.post(() -> {
            final IFace 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 FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
                    mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
                    challenge);

            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling revokeChallenge", e);
            }
        });
    }

@@ -398,20 +320,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
            @NonNull String opPackageName, @NonNull int[] disabledFeatures,
            @Nullable NativeHandle previewSurface, boolean debugConsent) {
        mHandler.post(() -> {
            final IFace 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 FaceEnrollClient client = new FaceEnrollClient(mContext,
@@ -430,9 +338,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
                    }
                }
            });
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling enroll", e);
            }
        });
    }

@@ -447,20 +352,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
            @NonNull String opPackageName, boolean restricted, int statsClient,
            boolean allowBackgroundAuthentication) {
        mHandler.post(() -> {
            final IFace 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 FaceAuthenticationClient client = new FaceAuthenticationClient(
                    mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
@@ -469,9 +360,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
                    mUsageStats, mSensors.get(sensorId).getLockoutCache(),
                    allowBackgroundAuthentication);
            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
            }
        });
    }

@@ -503,56 +391,24 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    private void scheduleRemoveSpecifiedIds(int sensorId, @NonNull IBinder token, int[] faceIds,
            int userId, @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) {
        mHandler.post(() -> {
            final IFace 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 FaceRemovalClient client = new FaceRemovalClient(mContext,
                    mSensors.get(sensorId).getLazySession(), token,
                    new ClientMonitorCallbackConverter(receiver), faceIds, userId,
                    opPackageName, FaceUtils.getInstance(sensorId), sensorId,
                    mSensors.get(sensorId).getAuthenticatorIds());

            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling remove", e);
            }
        });
    }

    @Override
    public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) {
        mHandler.post(() -> {
            final IFace 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 FaceResetLockoutClient client = new FaceResetLockoutClient(
                    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);
            }
        });
    }

@@ -580,17 +436,6 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
    public void scheduleInternalCleanup(int sensorId, int userId,
            @Nullable BaseClientMonitor.Callback callback) {
        mHandler.post(() -> {
            final IFace 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<Face> enrolledList = getEnrolledFaces(sensorId, userId);
            final FaceInternalCleanupClient client =
                    new FaceInternalCleanupClient(mContext,
@@ -598,11 +443,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
                            mContext.getOpPackageName(), sensorId, enrolledList,
                            FaceUtils.getInstance(sensorId),
                            mSensors.get(sensorId).getAuthenticatorIds());

            scheduleForSensor(sensorId, client);
            } catch (RemoteException e) {
                Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e);
            }
        });
    }

Loading