Finish TestSession implementation for FaceProvider
Also moves static classes to top in face/aidl/Sensor.java Bug: 173453845 Test: atest CtsBiometricsTestCases Change-Id: I9220747161e3842494ac7d02c1c472037718a9f9
This commit is contained in:
@@ -564,6 +564,11 @@ public class BiometricScheduler {
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println("Dump of BiometricScheduler " + getTag());
|
||||
pw.println("Current operation: " + mCurrentOperation);
|
||||
pw.println("Pending operations: " + mPendingOperations.size());
|
||||
for (Operation operation : mPendingOperations) {
|
||||
pw.println("Pending operation: " + operation);
|
||||
}
|
||||
for (CrashState crashState : mCrashStates) {
|
||||
pw.println("Crash State " + crashState);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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 static android.Manifest.permission.TEST_BIOMETRIC;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.hardware.biometrics.ITestSession;
|
||||
import android.hardware.face.Face;
|
||||
import android.hardware.face.IFaceServiceReceiver;
|
||||
import android.os.Binder;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.server.biometrics.HardwareAuthTokenUtils;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.sensors.face.FaceUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A test session implementation for {@link FaceProvider}. See
|
||||
* {@link android.hardware.biometrics.BiometricTestSession}.
|
||||
*/
|
||||
public class BiometricTestSessionImpl extends ITestSession.Stub {
|
||||
|
||||
private static final String TAG = "BiometricTestSessionImpl";
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
private final int mSensorId;
|
||||
@NonNull private final FaceProvider mProvider;
|
||||
@NonNull private final Sensor mSensor;
|
||||
@NonNull private final Set<Integer> mEnrollmentIds;
|
||||
@NonNull private final Random mRandom;
|
||||
|
||||
/**
|
||||
* Internal receiver currently only used for enroll. Results do not need to be forwarded to the
|
||||
* test, since enrollment is a platform-only API. The authentication path is tested through
|
||||
* the public BiometricPrompt APIs and does not use this receiver.
|
||||
*/
|
||||
private final IFaceServiceReceiver mReceiver = new IFaceServiceReceiver.Stub() {
|
||||
@Override
|
||||
public void onEnrollResult(Face face, int remaining) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAcquired(int acquireInfo, int vendorCode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(int error, int vendorCode) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(Face face, int remaining) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureSet(boolean success, int feature) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFeatureGet(boolean success, int feature, boolean value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChallengeGenerated(int sensorId, long challenge) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChallengeInterrupted(int sensorId) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChallengeInterruptFinished(int sensorId) {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
BiometricTestSessionImpl(@NonNull Context context, int sensorId,
|
||||
@NonNull FaceProvider provider, @NonNull Sensor sensor) {
|
||||
mContext = context;
|
||||
mSensorId = sensorId;
|
||||
mProvider = provider;
|
||||
mSensor = sensor;
|
||||
mEnrollmentIds = new HashSet<>();
|
||||
mRandom = new Random();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTestHalEnabled(boolean enabled) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mProvider.setTestHalEnabled(enabled);
|
||||
mSensor.setTestHalEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startEnroll(int userId) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
|
||||
mContext.getOpPackageName(), new int[0] /* disabledFeatures */, null /* surface */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishEnroll(int userId) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
int nextRandomId = mRandom.nextInt();
|
||||
while (mEnrollmentIds.contains(nextRandomId)) {
|
||||
nextRandomId = mRandom.nextInt();
|
||||
}
|
||||
|
||||
mEnrollmentIds.add(nextRandomId);
|
||||
mSensor.getSessionForUser(userId).mHalSessionCallback
|
||||
.onEnrollmentProgress(nextRandomId, 0 /* remaining */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptAuthentication(int userId) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
// Fake authentication with any of the existing faces
|
||||
List<Face> faces = FaceUtils.getInstance(mSensorId)
|
||||
.getBiometricsForUser(mContext, userId);
|
||||
if (faces.isEmpty()) {
|
||||
Slog.w(TAG, "No faces, returning");
|
||||
return;
|
||||
}
|
||||
final int fid = faces.get(0).getBiometricId();
|
||||
mSensor.getSessionForUser(userId).mHalSessionCallback.onAuthenticationSucceeded(fid,
|
||||
HardwareAuthTokenUtils.toHardwareAuthToken(new byte[69]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rejectAuthentication(int userId) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mSensor.getSessionForUser(userId).mHalSessionCallback.onAuthenticationFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAcquired(int userId, int acquireInfo) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mSensor.getSessionForUser(userId).mHalSessionCallback
|
||||
.onAcquired((byte) acquireInfo, 0 /* vendorCode */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyError(int userId, int errorCode) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mSensor.getSessionForUser(userId).mHalSessionCallback.onError((byte) errorCode,
|
||||
0 /* vendorCode */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cleanupInternalState(int userId) {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
mProvider.scheduleInternalCleanup(mSensorId, userId);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,11 @@ class FaceGetAuthenticatorIdClient extends ClientMonitor<ISession> {
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
|
||||
@@ -67,6 +67,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
private static final String TAG = "FaceProvider";
|
||||
private static final int ENROLL_TIMEOUT_SEC = 75;
|
||||
|
||||
private boolean mTestHalEnabled;
|
||||
|
||||
@NonNull private final Context mContext;
|
||||
@NonNull private final String mHalInstanceName;
|
||||
@NonNull private final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
|
||||
@@ -150,6 +152,10 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
|
||||
@Nullable
|
||||
private synchronized IFace getHalInstance() {
|
||||
if (mTestHalEnabled) {
|
||||
return new TestHal();
|
||||
}
|
||||
|
||||
if (mDaemon != null) {
|
||||
return mDaemon;
|
||||
}
|
||||
@@ -525,7 +531,9 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
|
||||
@Override
|
||||
public void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
|
||||
|
||||
if (mSensors.contains(sensorId)) {
|
||||
mSensors.get(sensorId).dumpProtoState(sensorId, proto);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -576,7 +584,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
@NonNull
|
||||
@Override
|
||||
public ITestSession createTestSession(int sensorId, @NonNull String opPackageName) {
|
||||
return null; // TODO
|
||||
return mSensors.get(sensorId).createTestSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -590,4 +598,8 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setTestHalEnabled(boolean enabled) {
|
||||
mTestHalEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,11 @@ public class FaceResetLockoutClient extends ClientMonitor<ISession> {
|
||||
// Nothing to do here
|
||||
}
|
||||
|
||||
public void start(@NonNull Callback callback) {
|
||||
super.start(callback);
|
||||
startHalOperation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startHalOperation() {
|
||||
try {
|
||||
|
||||
@@ -19,7 +19,9 @@ package com.android.server.biometrics.sensors.face.aidl;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.biometrics.BiometricsProtoEnums;
|
||||
import android.hardware.biometrics.ITestSession;
|
||||
import android.hardware.biometrics.face.Error;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
@@ -31,10 +33,15 @@ import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserManager;
|
||||
import android.util.Slog;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.server.biometrics.HardwareAuthTokenUtils;
|
||||
import com.android.server.biometrics.SensorServiceStateProto;
|
||||
import com.android.server.biometrics.SensorStateProto;
|
||||
import com.android.server.biometrics.UserStateProto;
|
||||
import com.android.server.biometrics.Utils;
|
||||
import com.android.server.biometrics.sensors.AcquisitionClient;
|
||||
import com.android.server.biometrics.sensors.AuthenticationConsumer;
|
||||
@@ -56,6 +63,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class Sensor implements IBinder.DeathRecipient {
|
||||
|
||||
private boolean mTestHalEnabled;
|
||||
|
||||
@NonNull private final String mTag;
|
||||
@NonNull private final FaceProvider mProvider;
|
||||
@NonNull private final Context mContext;
|
||||
@@ -67,27 +76,6 @@ public class Sensor implements IBinder.DeathRecipient {
|
||||
@NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
|
||||
@Nullable private Session mCurrentSession;
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Slog.e(mTag, "Binder died");
|
||||
mHandler.post(() -> {
|
||||
final ClientMonitor<?> client = mScheduler.getCurrentClient();
|
||||
if (client instanceof Interruptable) {
|
||||
Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
|
||||
final Interruptable interruptable = (Interruptable) client;
|
||||
interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FACE,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
mCurrentSession = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class Session {
|
||||
@NonNull final HalSessionCallback mHalSessionCallback;
|
||||
@NonNull private final String mTag;
|
||||
@@ -104,67 +92,6 @@ public class Sensor implements IBinder.DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
|
||||
@NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties) {
|
||||
mTag = tag;
|
||||
mProvider = provider;
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mSensorProperties = sensorProperties;
|
||||
mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
|
||||
mLockoutCache = new LockoutCache();
|
||||
mAuthenticatorIds = new HashMap<>();
|
||||
mLazySession = () -> (mCurrentSession != null) ? mCurrentSession.mSession : null;
|
||||
}
|
||||
|
||||
@NonNull ClientMonitor.LazyDaemon<ISession> getLazySession() {
|
||||
return mLazySession;
|
||||
}
|
||||
|
||||
@NonNull FaceSensorPropertiesInternal getSensorProperties() {
|
||||
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;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
newSession.asBinder().linkToDeath(this, 0 /* flags */);
|
||||
mCurrentSession = new Session(mTag, newSession, userId, resultController);
|
||||
}
|
||||
|
||||
@NonNull BiometricScheduler getScheduler() {
|
||||
return mScheduler;
|
||||
}
|
||||
|
||||
@NonNull LockoutCache getLockoutCache() {
|
||||
return mLockoutCache;
|
||||
}
|
||||
|
||||
@NonNull Map<Integer, Long> getAuthenticatorIds() {
|
||||
return mAuthenticatorIds;
|
||||
}
|
||||
|
||||
static class HalSessionCallback extends ISessionCallback.Stub {
|
||||
/**
|
||||
* Interface to sends results to the HalSessionCallback's owner.
|
||||
@@ -453,4 +380,120 @@ public class Sensor implements IBinder.DeathRecipient {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Sensor(@NonNull String tag, @NonNull FaceProvider provider, @NonNull Context context,
|
||||
@NonNull Handler handler, @NonNull FaceSensorPropertiesInternal sensorProperties) {
|
||||
mTag = tag;
|
||||
mProvider = provider;
|
||||
mContext = context;
|
||||
mHandler = handler;
|
||||
mSensorProperties = sensorProperties;
|
||||
mScheduler = new BiometricScheduler(tag, null /* gestureAvailabilityDispatcher */);
|
||||
mLockoutCache = new LockoutCache();
|
||||
mAuthenticatorIds = new HashMap<>();
|
||||
mLazySession = () -> {
|
||||
if (mTestHalEnabled) {
|
||||
return new TestSession(mCurrentSession.mHalSessionCallback);
|
||||
} else {
|
||||
return mCurrentSession != null ? mCurrentSession.mSession : null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull ClientMonitor.LazyDaemon<ISession> getLazySession() {
|
||||
return mLazySession;
|
||||
}
|
||||
|
||||
@NonNull FaceSensorPropertiesInternal getSensorProperties() {
|
||||
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;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull ITestSession createTestSession() {
|
||||
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, 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);
|
||||
newSession.asBinder().linkToDeath(this, 0 /* flags */);
|
||||
mCurrentSession = new Session(mTag, newSession, userId, resultController);
|
||||
}
|
||||
|
||||
@NonNull BiometricScheduler getScheduler() {
|
||||
return mScheduler;
|
||||
}
|
||||
|
||||
@NonNull LockoutCache getLockoutCache() {
|
||||
return mLockoutCache;
|
||||
}
|
||||
|
||||
@NonNull Map<Integer, Long> getAuthenticatorIds() {
|
||||
return mAuthenticatorIds;
|
||||
}
|
||||
|
||||
void setTestHalEnabled(boolean enabled) {
|
||||
mTestHalEnabled = enabled;
|
||||
}
|
||||
|
||||
void dumpProtoState(int sensorId, @NonNull ProtoOutputStream proto) {
|
||||
final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES);
|
||||
|
||||
proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId);
|
||||
proto.write(SensorStateProto.IS_BUSY, mScheduler.getCurrentClient() != null);
|
||||
|
||||
for (UserInfo user : UserManager.get(mContext).getUsers()) {
|
||||
final int userId = user.getUserHandle().getIdentifier();
|
||||
|
||||
final long userToken = proto.start(SensorStateProto.USER_STATES);
|
||||
proto.write(UserStateProto.USER_ID, userId);
|
||||
proto.write(UserStateProto.NUM_ENROLLED,
|
||||
FaceUtils.getInstance(mSensorProperties.sensorId)
|
||||
.getBiometricsForUser(mContext, userId).size());
|
||||
proto.end(userToken);
|
||||
}
|
||||
|
||||
proto.end(sensorToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Slog.e(mTag, "Binder died");
|
||||
mHandler.post(() -> {
|
||||
final ClientMonitor<?> client = mScheduler.getCurrentClient();
|
||||
if (client instanceof Interruptable) {
|
||||
Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
|
||||
final Interruptable interruptable = (Interruptable) client;
|
||||
interruptable.onError(FaceManager.FACE_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FACE,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
mCurrentSession = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.hardware.biometrics.common.ICancellationSignal;
|
||||
import android.hardware.biometrics.face.IFace;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.hardware.biometrics.face.ISessionCallback;
|
||||
import android.hardware.biometrics.face.SensorProps;
|
||||
import android.hardware.common.NativeHandle;
|
||||
import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
|
||||
/**
|
||||
* Test HAL that provides only no-ops.
|
||||
*/
|
||||
public class TestHal extends IFace.Stub {
|
||||
@Override
|
||||
public SensorProps[] getSensorProps() {
|
||||
return new SensorProps[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISession createSession(int sensorId, int userId, ISessionCallback cb) {
|
||||
return new ISession() {
|
||||
@Override
|
||||
public void generateChallenge(int cookie, int timeoutSec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeChallenge(int cookie, long challenge) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal enroll(int cookie, HardwareAuthToken hat,
|
||||
NativeHandle previewSurface) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal authenticate(int cookie, long operationId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal detectInteraction(int cookie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enumerateEnrollments(int cookie) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEnrollments(int cookie, int[] enrollmentIds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAuthenticatorId(int cookie) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateAuthenticatorId(int cookie) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLockout(int cookie, HardwareAuthToken hat) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return new Binder();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.hardware.biometrics.common.ICancellationSignal;
|
||||
import android.hardware.biometrics.face.Error;
|
||||
import android.hardware.biometrics.face.ISession;
|
||||
import android.hardware.common.NativeHandle;
|
||||
import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
|
||||
/**
|
||||
* Test session that provides mostly no-ops.
|
||||
*/
|
||||
public class TestSession extends ISession.Stub {
|
||||
private static final String TAG = "TestSession";
|
||||
|
||||
@NonNull
|
||||
private final Sensor.HalSessionCallback mHalSessionCallback;
|
||||
|
||||
TestSession(@NonNull Sensor.HalSessionCallback halSessionCallback) {
|
||||
mHalSessionCallback = halSessionCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateChallenge(int cookie, int timeoutSec) {
|
||||
mHalSessionCallback.onChallengeGenerated(0 /* challenge */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeChallenge(int cookie, long challenge) {
|
||||
mHalSessionCallback.onChallengeRevoked(challenge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal enroll(int cookie, HardwareAuthToken hat,
|
||||
NativeHandle previewSurface) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal authenticate(int cookie, long operationId) {
|
||||
return new ICancellationSignal() {
|
||||
@Override
|
||||
public void cancel() throws RemoteException {
|
||||
mHalSessionCallback.onError(Error.CANCELED, 0 /* vendorCode */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder asBinder() {
|
||||
return new Binder();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICancellationSignal detectInteraction(int cookie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enumerateEnrollments(int cookie) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEnrollments(int cookie, int[] enrollmentIds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getAuthenticatorId(int cookie) {
|
||||
mHalSessionCallback.onAuthenticatorIdRetrieved(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateAuthenticatorId(int cookie) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetLockout(int cookie, HardwareAuthToken hat) {
|
||||
mHalSessionCallback.onLockoutCleared();
|
||||
}
|
||||
}
|
||||
@@ -143,7 +143,7 @@ class BiometricTestSessionImpl extends ITestSession.Stub {
|
||||
Utils.checkPermission(mContext, TEST_BIOMETRIC);
|
||||
|
||||
// Fake authentication with any of the existing fingers
|
||||
List<Fingerprint> fingerprints = FingerprintUtils.getInstance()
|
||||
List<Fingerprint> fingerprints = FingerprintUtils.getInstance(mSensorId)
|
||||
.getBiometricsForUser(mContext, userId);
|
||||
if (fingerprints.isEmpty()) {
|
||||
Slog.w(TAG, "No fingerprints, returning");
|
||||
|
||||
@@ -80,27 +80,6 @@ class Sensor implements IBinder.DeathRecipient {
|
||||
@Nullable private Session mCurrentSession;
|
||||
@NonNull private final ClientMonitor.LazyDaemon<ISession> mLazySession;
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Slog.e(mTag, "Binder died");
|
||||
mHandler.post(() -> {
|
||||
final ClientMonitor<?> client = mScheduler.getCurrentClient();
|
||||
if (client instanceof Interruptable) {
|
||||
Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
|
||||
final Interruptable interruptable = (Interruptable) client;
|
||||
interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FINGERPRINT,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
mCurrentSession = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static class Session {
|
||||
@NonNull private final String mTag;
|
||||
@NonNull private final ISession mSession;
|
||||
@@ -501,11 +480,33 @@ class Sensor implements IBinder.DeathRecipient {
|
||||
|
||||
final long userToken = proto.start(SensorStateProto.USER_STATES);
|
||||
proto.write(UserStateProto.USER_ID, userId);
|
||||
proto.write(UserStateProto.NUM_ENROLLED, FingerprintUtils.getInstance()
|
||||
.getBiometricsForUser(mContext, userId).size());
|
||||
proto.write(UserStateProto.NUM_ENROLLED,
|
||||
FingerprintUtils.getInstance(mSensorProperties.sensorId)
|
||||
.getBiometricsForUser(mContext, userId).size());
|
||||
proto.end(userToken);
|
||||
}
|
||||
|
||||
proto.end(sensorToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
Slog.e(mTag, "Binder died");
|
||||
mHandler.post(() -> {
|
||||
final ClientMonitor<?> client = mScheduler.getCurrentClient();
|
||||
if (client instanceof Interruptable) {
|
||||
Slog.e(mTag, "Sending ERROR_HW_UNAVAILABLE for client: " + client);
|
||||
final Interruptable interruptable = (Interruptable) client;
|
||||
interruptable.onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
|
||||
0 /* vendorCode */);
|
||||
|
||||
mScheduler.recordCrashState();
|
||||
|
||||
FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
|
||||
BiometricsProtoEnums.MODALITY_FINGERPRINT,
|
||||
BiometricsProtoEnums.ISSUE_HAL_DEATH);
|
||||
mCurrentSession = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.hardware.keymaster.HardwareAuthToken;
|
||||
import android.util.Slog;
|
||||
|
||||
/**
|
||||
* Test HAL that provides only provides mostly no-ops.
|
||||
* Test session that provides mostly no-ops.
|
||||
*/
|
||||
class TestSession extends ISession.Stub {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user