4/n: Add and use Face AIDL start/stop user clients

Bug: 181984005
Test: atest CtsBiometricsTestCases
Test: atest com.android.server.biometrics
Change-Id: I1b62b12d3b99fd572450316168b6cea2c7a06e16
This commit is contained in:
Kevin Chyn
2021-03-22 14:27:56 -07:00
parent bcb85a9a71
commit 86e98080b1
5 changed files with 270 additions and 247 deletions

View File

@@ -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;
}
final FaceGetAuthenticatorIdClient client = new FaceGetAuthenticatorIdClient(
mContext, mSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId,
mSensors.get(sensorId).getAuthenticatorIds());
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);
}
scheduleForSensor(sensorId, client);
});
}
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);
}
final FaceInvalidationClient client = new FaceInvalidationClient(mContext,
mSensors.get(sensorId).getLazySession(), userId, sensorId,
mSensors.get(sensorId).getAuthenticatorIds(), callback);
scheduleForSensor(sensorId, client);
});
}
@@ -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);
}
final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), opPackageName, sensorId);
scheduleForSensor(sensorId, client);
});
}
@@ -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);
}
final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext,
mSensors.get(sensorId).getLazySession(), token, opPackageName, sensorId,
challenge);
scheduleForSensor(sensorId, client);
});
}
@@ -398,41 +320,24 @@ 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,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
debugConsent);
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 FaceEnrollClient client = new FaceEnrollClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FaceUtils.getInstance(sensorId), disabledFeatures,
ENROLL_TIMEOUT_SEC, previewSurface, sensorId, maxTemplatesPerUser,
debugConsent);
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);
}
}
});
});
}
@@ -447,31 +352,14 @@ 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,
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication);
scheduleForSensor(sensorId, client);
} catch (RemoteException e) {
Slog.e(getTag(), "Remote exception when scheduling authenticate", e);
}
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication);
scheduleForSensor(sensorId, client);
});
}
@@ -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);
}
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);
});
}
@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;
}
final FaceResetLockoutClient client = new FaceResetLockoutClient(
mContext, mSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId, hardwareAuthToken,
mSensors.get(sensorId).getLockoutCache(), mLockoutResetDispatcher);
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);
}
scheduleForSensor(sensorId, client);
});
}
@@ -580,29 +436,14 @@ 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,
mSensors.get(sensorId).getLazySession(), userId,
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);
}
final List<Face> enrolledList = getEnrolledFaces(sensorId, userId);
final FaceInternalCleanupClient client =
new FaceInternalCleanupClient(mContext,
mSensors.get(sensorId).getLazySession(), userId,
mContext.getOpPackageName(), sensorId, enrolledList,
FaceUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
scheduleForSensor(sensorId, client);
});
}

View File

@@ -0,0 +1,67 @@
/*
* 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.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.ISession;
import android.hardware.biometrics.face.ISessionCallback;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.StartUserClient;
public class FaceStartUserClient extends StartUserClient<IFace, ISession> {
private static final String TAG = "FaceStartUserClient";
@NonNull private final ISessionCallback mSessionCallback;
public FaceStartUserClient(@NonNull Context context, @NonNull LazyDaemon<IFace> 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.face.aidl;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.face.ISession;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.StopUserClient;
public class FaceStopUserClient extends StopUserClient<ISession> {
private static final String TAG = "FaceStopUserClient";
public FaceStopUserClient(@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

@@ -33,8 +33,11 @@ import android.hardware.face.Face;
import android.hardware.face.FaceManager;
import android.hardware.face.FaceSensorPropertiesInternal;
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;
@@ -54,6 +57,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.face.FaceUtils;
import java.util.ArrayList;
@@ -70,9 +76,10 @@ public class Sensor {
@NonNull private final String mTag;
@NonNull private final FaceProvider mProvider;
@NonNull private final Context mContext;
@NonNull private final IBinder mToken;
@NonNull private final Handler mHandler;
@NonNull private final FaceSensorPropertiesInternal mSensorProperties;
@NonNull private final BiometricScheduler mScheduler;
@NonNull private final UserAwareBiometricScheduler mScheduler;
@NonNull private final LockoutCache mLockoutCache;
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@NonNull private final HalClientMonitor.LazyDaemon<ISession> mLazySession;
@@ -427,7 +434,15 @@ public class Sensor {
@Override
public void onSessionClosed() {
mHandler.post(() -> {
// TODO: implement this.
final BaseClientMonitor client = mScheduler.getCurrentClient();
if (!(client instanceof FaceStopUserClient)) {
Slog.e(mTag, "onSessionClosed for wrong consumer: "
+ Utils.getClientName(client));
return;
}
final FaceStopUserClient stopUserClient = (FaceStopUserClient) client;
stopUserClient.onUserStopped();
});
}
}
@@ -437,9 +452,53 @@ public class Sensor {
mTag = tag;
mProvider = provider;
mContext = context;
mToken = new Binder();
mHandler = handler;
mSensorProperties = sensorProperties;
mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
mScheduler = new UserAwareBiometricScheduler(tag, null /* gestureAvailabilityDispatcher */,
() -> mCurrentSession != null ? mCurrentSession.mUserId : UserHandle.USER_NULL,
new UserAwareBiometricScheduler.UserSwitchCallback() {
@NonNull
@Override
public StopUserClient<?> getStopUserClient(int userId) {
return new FaceStopUserClient(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 (FaceUtils.getLegacyInstance(sensorId)
.isInvalidationInProgress(mContext, userIdStarted)) {
Slog.w(mTag,
"Scheduling unfinished invalidation request for "
+ "sensor: "
+ sensorId
+ ", user: " + userIdStarted);
provider.scheduleInvalidationRequest(sensorId,
userIdStarted);
}
};
return new FaceStartUserClient(mContext, provider::getHalInstance,
mToken, newUserId, mSensorProperties.sensorId,
resultController, userStartedCallback);
}
});
mLockoutCache = new LockoutCache();
mAuthenticatorIds = new HashMap<>();
mLazySession = () -> mCurrentSession != null ? mCurrentSession.mSession : null;
@@ -453,11 +512,6 @@ public 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;
@@ -471,20 +525,6 @@ public class Sensor {
mProvider, this);
}
void createNewSession(@NonNull IFace 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

@@ -24,10 +24,12 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.biometrics.common.CommonProps;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
import android.os.UserManager;
import android.platform.test.annotations.Presubmit;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -56,7 +58,7 @@ public class FaceProviderTest {
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
private FaceProvider mFaceProvider;
private TestableFaceProvider mFaceProvider;
private static void waitForIdle() {
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
@@ -80,7 +82,7 @@ public class FaceProviderTest {
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
mFaceProvider = new FaceProvider(mContext, mSensorProps, TAG,
mFaceProvider = new TestableFaceProvider(mContext, mSensorProps, TAG,
mLockoutResetDispatcher);
}
@@ -123,4 +125,19 @@ public class FaceProviderTest {
assertEquals(0, scheduler.getCurrentPendingCount());
}
}
private static class TestableFaceProvider extends FaceProvider {
public TestableFaceProvider(@NonNull Context context,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, props, halInstanceName, lockoutResetDispatcher);
}
@Override
synchronized IFace getHalInstance() {
return mock(IFace.class);
}
}
}