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
This commit is contained in:
Kevin Chyn
2021-03-22 11:57:42 -07:00
parent 302b408511
commit bcb85a9a71
11 changed files with 318 additions and 287 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;

View File

@@ -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();
}
};
}

View File

@@ -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);
}
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<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);
}
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<Fingerprint> 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<Fingerprint> 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);
});
}

View File

@@ -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<IFingerprint, ISession> {
private static final String TAG = "FingerprintStartUserClient";
@NonNull private final ISessionCallback mSessionCallback;
public FingerprintStartUserClient(@NonNull Context context,
@NonNull LazyDaemon<IFingerprint> lazyDaemon,
@Nullable IBinder token, int userId, int sensorId,
@NonNull ISessionCallback sessionCallback,
@NonNull UserStartedCallback<ISession> 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() {
}
}

View File

@@ -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<ISession> {
private static final String TAG = "FingerprintStopUserClient";
public FingerprintStopUserClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> 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() {
}
}

View File

@@ -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<Integer, Long> 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<ISession> 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;
}

View File

@@ -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

View File

@@ -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<Object> {
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<Object> {
private static class TestStartUserClient extends StartUserClient<Object, Object> {
public TestStartUserClient(@NonNull Context context,
@NonNull LazyDaemon<Object> lazyDaemon, @Nullable IBinder token, int userId,
int sensorId, @NonNull UserStartedCallback callback) {
int sensorId, @NonNull UserStartedCallback<Object> 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 */);
}

View File

@@ -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);
}
}
}