From bcb85a9a71c567169fb1fc16dc2d5a59faa279b6 Mon Sep 17 00:00:00 2001 From: Kevin Chyn Date: Mon, 22 Mar 2021 11:57:42 -0700 Subject: [PATCH] 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 --- .../biometrics/sensors/StartUserClient.java | 19 +- .../biometrics/sensors/StopUserClient.java | 11 +- .../sensors/UserAwareBiometricScheduler.java | 2 +- .../biometrics/sensors/face/aidl/TestHal.java | 3 +- .../fingerprint/aidl/FingerprintProvider.java | 319 ++++-------------- .../aidl/FingerprintStartUserClient.java | 68 ++++ .../aidl/FingerprintStopUserClient.java | 58 ++++ .../sensors/fingerprint/aidl/Sensor.java | 85 +++-- .../sensors/fingerprint/aidl/TestHal.java | 3 +- .../UserAwareBiometricSchedulerTest.java | 15 +- .../aidl/FingerprintProviderTest.java | 22 +- 11 files changed, 318 insertions(+), 287 deletions(-) create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java create mode 100644 services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java diff --git a/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java index 8b9be83bc8c36..3d6932639c1c2 100644 --- a/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/StartUserClient.java @@ -25,18 +25,27 @@ import android.os.IBinder; import com.android.internal.annotations.VisibleForTesting; import com.android.server.biometrics.BiometricsProto; -public abstract class StartUserClient extends HalClientMonitor { +/** + * Abstract class for starting a new user. + * @param Interface to request a new user. + * @param Newly created user object. + */ +public abstract class StartUserClient extends HalClientMonitor { - public interface UserStartedCallback { - void onUserStarted(int newUserId); + /** + * Invoked when the new user is started. + * @param New user object. + */ + public interface UserStartedCallback { + void onUserStarted(int newUserId, U newUser); } @NonNull @VisibleForTesting - protected final UserStartedCallback mUserStartedCallback; + protected final UserStartedCallback mUserStartedCallback; public StartUserClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, @Nullable IBinder token, int userId, int sensorId, - @NonNull UserStartedCallback callback) { + @NonNull UserStartedCallback callback) { super(context, lazyDaemon, token, null /* listener */, userId, context.getOpPackageName(), 0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN); diff --git a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java index 62cd673babac7..1f6e1e95050d4 100644 --- a/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java +++ b/services/core/java/com/android/server/biometrics/sensors/StopUserClient.java @@ -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 Interface for stopping the user. + */ public abstract class StopUserClient extends HalClientMonitor { public interface UserStoppedCallback { @@ -32,7 +36,12 @@ public abstract class StopUserClient extends HalClientMonitor { } @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 lazyDaemon, @Nullable IBinder token, int userId, int sensorId, diff --git a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java index c0ea2b3f8b933..4d390a4f9059e 100644 --- a/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java +++ b/services/core/java/com/android/server/biometrics/sensors/UserAwareBiometricScheduler.java @@ -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; diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java index 4ca85d000d194..36327bb5c21a9 100644 --- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java +++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/TestHal.java @@ -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(); } }; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java index bcca69b3ad352..972071c6f3eeb 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java @@ -82,7 +82,6 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi @NonNull private final String mHalInstanceName; @NonNull @VisibleForTesting final SparseArray mSensors; // Map of sensors that this HAL supports - @NonNull private final HalClientMonitor.LazyDaemon 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); - } + final FingerprintGetAuthenticatorIdClient client = + new FingerprintGetAuthenticatorIdClient(mContext, + mSensors.get(sensorId).getLazySession(), userId, + mContext.getOpPackageName(), sensorId, + mSensors.get(sensorId).getAuthenticatorIds()); + scheduleForSensor(sensorId, client); }); } - private void scheduleInvalidationRequest(int sensorId, int userId) { + void scheduleInvalidationRequest(int sensorId, int userId) { mHandler.post(() -> { final InvalidationRequesterClient 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); - } + final FingerprintResetLockoutClient client = new FingerprintResetLockoutClient( + mContext, mSensors.get(sensorId).getLazySession(), userId, + mContext.getOpPackageName(), sensorId, hardwareAuthToken, + mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher); + scheduleForSensor(sensorId, client); }); } @@ -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); - } + final FingerprintGenerateChallengeClient client = + new FingerprintGenerateChallengeClient(mContext, + mSensors.get(sensorId).getLazySession(), token, + new ClientMonitorCallbackConverter(receiver), opPackageName, + sensorId); + scheduleForSensor(sensorId, client); }); } @@ -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); - } + final FingerprintRevokeChallengeClient client = + new FingerprintRevokeChallengeClient(mContext, + mSensors.get(sensorId).getLazySession(), token, + opPackageName, sensorId, challenge); + scheduleForSensor(sensorId, client); }); } @@ -392,40 +318,23 @@ 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, - mSensors.get(sensorId).getLazySession(), token, - new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, - opPackageName, FingerprintUtils.getInstance(sensorId), sensorId, - mUdfpsOverlayController, maxTemplatesPerUser, enrollReason); - scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() { - @Override - public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, - boolean success) { - if (success) { - scheduleLoadAuthenticatorIdsForUser(sensorId, userId); - scheduleInvalidationRequest(sensorId, userId); - } + final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties() + .maxEnrollmentsPerUser; + final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext, + mSensors.get(sensorId).getLazySession(), token, + new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, + opPackageName, FingerprintUtils.getInstance(sensorId), sensorId, + mUdfpsOverlayController, maxTemplatesPerUser, enrollReason); + scheduleForSensor(sensorId, client, new BaseClientMonitor.Callback() { + @Override + public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, + boolean success) { + if (success) { + scheduleLoadAuthenticatorIdsForUser(sensorId, userId); + scheduleInvalidationRequest(sensorId, userId); } - }); - } 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); - } + 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); }); } @@ -471,31 +363,14 @@ 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, - operationId, restricted, opPackageName, cookie, - false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, - mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), - mUdfpsOverlayController, allowBackgroundAuthentication); - scheduleForSensor(sensorId, client); - } catch (RemoteException e) { - Slog.e(getTag(), "Remote exception when scheduling authenticate", e); - } + final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId); + final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient( + mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId, + operationId, restricted, opPackageName, cookie, + false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient, + mTaskStackListener, mSensors.get(sensorId).getLockoutCache(), + mUdfpsOverlayController, allowBackgroundAuthentication); + scheduleForSensor(sensorId, client); }); } @@ -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); - } + 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); }); } @@ -565,28 +423,14 @@ 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 enrolledList = getEnrolledFingerprints(sensorId, userId); - final FingerprintInternalCleanupClient client = - new FingerprintInternalCleanupClient(mContext, - mSensors.get(sensorId).getLazySession(), userId, - mContext.getOpPackageName(), sensorId, enrolledList, - FingerprintUtils.getInstance(sensorId), - mSensors.get(sensorId).getAuthenticatorIds()); - scheduleForSensor(sensorId, client); - } catch (RemoteException e) { - Slog.e(getTag(), "Remote exception when scheduling internal cleanup", e); - } + final List enrolledList = getEnrolledFingerprints(sensorId, userId); + final FingerprintInternalCleanupClient client = + new FingerprintInternalCleanupClient(mContext, + mSensors.get(sensorId).getLazySession(), userId, + mContext.getOpPackageName(), sensorId, enrolledList, + FingerprintUtils.getInstance(sensorId), + mSensors.get(sensorId).getAuthenticatorIds()); + scheduleForSensor(sensorId, client); }); } @@ -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); - } + final FingerprintInvalidationClient client = + new FingerprintInvalidationClient(mContext, + mSensors.get(sensorId).getLazySession(), userId, sensorId, + mSensors.get(sensorId).getAuthenticatorIds(), callback); + scheduleForSensor(sensorId, client); }); } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java new file mode 100644 index 0000000000000..2d40c91cbc754 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStartUserClient.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.biometrics.fingerprint.IFingerprint; +import android.hardware.biometrics.fingerprint.ISession; +import android.hardware.biometrics.fingerprint.ISessionCallback; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.StartUserClient; + +public class FingerprintStartUserClient extends StartUserClient { + private static final String TAG = "FingerprintStartUserClient"; + + @NonNull private final ISessionCallback mSessionCallback; + + public FingerprintStartUserClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, + @Nullable IBinder token, int userId, int sensorId, + @NonNull ISessionCallback sessionCallback, + @NonNull UserStartedCallback callback) { + super(context, lazyDaemon, token, userId, sensorId, callback); + mSessionCallback = sessionCallback; + } + + @Override + public void start(@NonNull Callback callback) { + super.start(callback); + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + final ISession newSession = getFreshDaemon().createSession(getSensorId(), + getTargetUserId(), mSessionCallback); + mUserStartedCallback.onUserStarted(getTargetUserId(), newSession); + getCallback().onClientFinished(this, true /* success */); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + getCallback().onClientFinished(this, false /* success */); + } + } + + @Override + public void unableToStart() { + + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java new file mode 100644 index 0000000000000..ba813578245c8 --- /dev/null +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintStopUserClient.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.biometrics.sensors.fingerprint.aidl; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.hardware.biometrics.fingerprint.ISession; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.biometrics.sensors.StopUserClient; + +public class FingerprintStopUserClient extends StopUserClient { + private static final String TAG = "FingerprintStopUserClient"; + + public FingerprintStopUserClient(@NonNull Context context, + @NonNull LazyDaemon lazyDaemon, @Nullable IBinder token, int userId, + int sensorId, @NonNull UserStoppedCallback callback) { + super(context, lazyDaemon, token, userId, sensorId, callback); + } + + @Override + public void start(@NonNull Callback callback) { + super.start(callback); + startHalOperation(); + } + + @Override + protected void startHalOperation() { + try { + getFreshDaemon().close(mSequentialId); + } catch (RemoteException e) { + Slog.e(TAG, "Remote exception", e); + getCallback().onClientFinished(this, false /* success */); + } + } + + @Override + public void unableToStart() { + + } +} diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java index d843bc94455c4..40ddfe91fbd07 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/Sensor.java @@ -24,15 +24,17 @@ import android.hardware.biometrics.BiometricsProtoEnums; import android.hardware.biometrics.ITestSession; import android.hardware.biometrics.ITestSessionCallback; import android.hardware.biometrics.fingerprint.Error; -import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.ISession; import android.hardware.biometrics.fingerprint.ISessionCallback; import android.hardware.fingerprint.Fingerprint; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.keymaster.HardwareAuthToken; +import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.RemoteException; +import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -53,6 +55,9 @@ import com.android.server.biometrics.sensors.Interruptable; import com.android.server.biometrics.sensors.LockoutCache; import com.android.server.biometrics.sensors.LockoutConsumer; import com.android.server.biometrics.sensors.RemovalConsumer; +import com.android.server.biometrics.sensors.StartUserClient; +import com.android.server.biometrics.sensors.StopUserClient; +import com.android.server.biometrics.sensors.UserAwareBiometricScheduler; import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils; import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; @@ -72,9 +77,10 @@ class Sensor { @NonNull private final String mTag; @NonNull private final FingerprintProvider mProvider; @NonNull private final Context mContext; + @NonNull private final IBinder mToken; @NonNull private final Handler mHandler; @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; - @NonNull private final BiometricScheduler mScheduler; + @NonNull private final UserAwareBiometricScheduler mScheduler; @NonNull private final LockoutCache mLockoutCache; @NonNull private final Map mAuthenticatorIds; @@ -407,7 +413,15 @@ class Sensor { @Override public void onSessionClosed() { mHandler.post(() -> { - // TODO: implement this. + final BaseClientMonitor client = mScheduler.getCurrentClient(); + if (!(client instanceof FingerprintStopUserClient)) { + Slog.e(mTag, "onSessionClosed for wrong consumer: " + + Utils.getClientName(client)); + return; + } + + final FingerprintStopUserClient stopUserClient = (FingerprintStopUserClient) client; + stopUserClient.onUserStopped(); }); } } @@ -418,9 +432,53 @@ class Sensor { mTag = tag; mProvider = provider; mContext = context; + mToken = new Binder(); mHandler = handler; mSensorProperties = sensorProperties; - mScheduler = new BiometricScheduler(tag, gestureAvailabilityDispatcher); + mScheduler = new UserAwareBiometricScheduler(tag, gestureAvailabilityDispatcher, + () -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL, + new UserAwareBiometricScheduler.UserSwitchCallback() { + @NonNull + @Override + public StopUserClient getStopUserClient(int userId) { + return new FingerprintStopUserClient(mContext, mLazySession, mToken, + userId, mSensorProperties.sensorId, () -> mCurrentSession = null); + } + + @NonNull + @Override + public StartUserClient getStartUserClient(int newUserId) { + final HalSessionCallback.Callback callback = () -> { + Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); + mCurrentSession = null; + }; + + final int sensorId = mSensorProperties.sensorId; + + final HalSessionCallback resultController = new HalSessionCallback(mContext, + mHandler, mTag, mScheduler, sensorId, newUserId, callback); + + final StartUserClient.UserStartedCallback userStartedCallback = + (userIdStarted, newSession) -> { + mCurrentSession = new Session(mTag, + newSession, userIdStarted, resultController); + if (FingerprintUtils.getInstance(sensorId) + .isInvalidationInProgress(mContext, userIdStarted)) { + Slog.w(mTag, + "Scheduling unfinished invalidation request for " + + "sensor: " + + sensorId + + ", user: " + userIdStarted); + provider.scheduleInvalidationRequest(sensorId, + userIdStarted); + } + }; + + return new FingerprintStartUserClient(mContext, provider::getHalInstance, + mToken, newUserId, mSensorProperties.sensorId, + resultController, userStartedCallback); + } + }); mLockoutCache = new LockoutCache(); mAuthenticatorIds = new HashMap<>(); mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null; @@ -434,11 +492,6 @@ class Sensor { return mSensorProperties; } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") - boolean hasSessionForUser(int userId) { - return mCurrentSession != null && mCurrentSession.mUserId == userId; - } - @Nullable Session getSessionForUser(int userId) { if (mCurrentSession != null && mCurrentSession.mUserId == userId) { return mCurrentSession; @@ -452,20 +505,6 @@ class Sensor { mProvider, this); } - void createNewSession(@NonNull IFingerprint daemon, int sensorId, int userId) - throws RemoteException { - - final HalSessionCallback.Callback callback = () -> { - Slog.e(mTag, "Got ERROR_HW_UNAVAILABLE"); - mCurrentSession = null; - }; - final HalSessionCallback resultController = new HalSessionCallback(mContext, mHandler, - mTag, mScheduler, sensorId, userId, callback); - - final ISession newSession = daemon.createSession(sensorId, userId, resultController); - mCurrentSession = new Session(mTag, newSession, userId, resultController); - } - @NonNull BiometricScheduler getScheduler() { return mScheduler; } diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java index 0b7f3abc9005a..31fc06818b905 100644 --- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java +++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/TestHal.java @@ -121,7 +121,8 @@ public class TestHal extends IFingerprint.Stub { @Override public void close(int cookie) throws RemoteException { - cb.onStateChanged(cookie, SessionState.CLOSED); + Slog.w(TAG, "close, cookie: " + cookie); + cb.onSessionClosed(); } @Override diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java index 6cdac1af87eb4..557c14a0dfc14 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/UserAwareBiometricSchedulerTest.java @@ -81,7 +81,7 @@ public class UserAwareBiometricSchedulerTest { @NonNull @Override - public StartUserClient getStartUserClient(int newUserId) { + public StartUserClient getStartUserClient(int newUserId) { return new TestStartUserClient(mContext, Object::new, mToken, newUserId, TEST_SENSOR_ID, mUserStartedCallback); } @@ -157,12 +157,12 @@ public class UserAwareBiometricSchedulerTest { } } - private class TestUserStartedCallback implements StartUserClient.UserStartedCallback { + private class TestUserStartedCallback implements StartUserClient.UserStartedCallback { int numInvocations; @Override - public void onUserStarted(int newUserId) { + public void onUserStarted(int newUserId, Object newObject) { numInvocations++; mCurrentUserId = newUserId; } @@ -183,8 +183,7 @@ public class UserAwareBiometricSchedulerTest { @Override public void start(@NonNull Callback callback) { super.start(callback); - mUserStoppedCallback.onUserStopped(); - callback.onClientFinished(this, true /* success */); + onUserStopped(); } @Override @@ -193,10 +192,10 @@ public class UserAwareBiometricSchedulerTest { } } - private static class TestStartUserClient extends StartUserClient { + private static class TestStartUserClient extends StartUserClient { public TestStartUserClient(@NonNull Context context, @NonNull LazyDaemon lazyDaemon, @Nullable IBinder token, int userId, - int sensorId, @NonNull UserStartedCallback callback) { + int sensorId, @NonNull UserStartedCallback callback) { super(context, lazyDaemon, token, userId, sensorId, callback); } @@ -208,7 +207,7 @@ public class UserAwareBiometricSchedulerTest { @Override public void start(@NonNull Callback callback) { super.start(callback); - mUserStartedCallback.onUserStarted(getTargetUserId()); + mUserStartedCallback.onUserStarted(getTargetUserId(), new Object()); callback.onClientFinished(this, true /* success */); } diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java index d149880e55059..94cc666d740cd 100644 --- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java @@ -24,10 +24,12 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.biometrics.common.CommonProps; +import android.hardware.biometrics.fingerprint.IFingerprint; import android.hardware.biometrics.fingerprint.SensorProps; import android.os.UserManager; import android.platform.test.annotations.Presubmit; +import androidx.annotation.NonNull; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -59,7 +61,7 @@ public class FingerprintProviderTest { private SensorProps[] mSensorProps; private LockoutResetDispatcher mLockoutResetDispatcher; - private FingerprintProvider mFingerprintProvider; + private TestableFingerprintProvider mFingerprintProvider; private static void waitForIdle() { InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -83,7 +85,7 @@ public class FingerprintProviderTest { mLockoutResetDispatcher = new LockoutResetDispatcher(mContext); - mFingerprintProvider = new FingerprintProvider(mContext, mSensorProps, TAG, + mFingerprintProvider = new TestableFingerprintProvider(mContext, mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher); } @@ -126,4 +128,20 @@ public class FingerprintProviderTest { assertEquals(0, scheduler.getCurrentPendingCount()); } } + + private static class TestableFingerprintProvider extends FingerprintProvider { + public TestableFingerprintProvider(@NonNull Context context, + @NonNull SensorProps[] props, + @NonNull String halInstanceName, + @NonNull LockoutResetDispatcher lockoutResetDispatcher, + @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { + super(context, props, halInstanceName, lockoutResetDispatcher, + gestureAvailabilityDispatcher); + } + + @Override + synchronized IFingerprint getHalInstance() { + return mock(IFingerprint.class); + } + } }