1/n: Add ClientMonitors for authenticatorId invalidation

InvalidationRequesterClient (for requesting other clients to
invalidate) will be fully implemented in subsequent CL's.

InvalidationClient (for requesting HALs to invalidate authenticatorId)
should be complete at this point.

Also updates BiometricUtils to persist a "invalidationInProgress"
flag on-disk for each <sensorId, userId> pair.

Bug: 159667191
Test: No effect on existing devices
Test: Existing enrollments not affected

Change-Id: I9eeb802b556ba86568cf41b456a4ceab4b896ef0
This commit is contained in:
Kevin Chyn
2021-01-08 14:18:13 -08:00
parent 8337a179d4
commit 907910685f
36 changed files with 381 additions and 131 deletions

View File

@@ -56,9 +56,9 @@ public abstract class AcquisitionClient<T> extends ClientMonitor<T> implements I
public AcquisitionClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality,
int statsAction, int statsClient, boolean shouldLogMetrics) {
int statsAction, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, cookie, sensorId, statsModality,
statsAction, statsClient, shouldLogMetrics);
statsAction, statsClient);
mPowerManager = context.getSystemService(PowerManager.class);
mSuccessVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
mErrorVibrationEffect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);

View File

@@ -66,8 +66,7 @@ public abstract class AuthenticationClient<T> extends AcquisitionClient<T>
int statsModality, int statsClient, @Nullable TaskStackListener taskStackListener,
@NonNull LockoutTracker lockoutTracker) {
super(context, lazyDaemon, token, listener, targetUserId, owner, cookie, sensorId,
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient,
true /* shouldLogMetrics */);
statsModality, BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
mIsStrongBiometric = isStrongBiometric;
mOperationId = operationId;
mRequireConfirmation = requireConfirmation;

View File

@@ -21,8 +21,10 @@ import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
@@ -35,6 +37,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -46,17 +49,16 @@ import java.util.List;
public abstract class BiometricUserState<T extends BiometricAuthenticator.Identifier> {
private static final String TAG = "UserState";
private static final String TAG_INVALIDATION = "authenticatorIdInvalidation_tag";
private static final String ATTR_INVALIDATION = "authenticatorIdInvalidation_attr";
@GuardedBy("this")
protected final ArrayList<T> mBiometrics = new ArrayList<>();
protected boolean mInvalidationInProgress;
protected final Context mContext;
protected final File mFile;
private final Runnable mWriteStateRunnable = new Runnable() {
@Override
public void run() {
doWriteState();
}
};
private final Runnable mWriteStateRunnable = this::doWriteStateInternal;
/**
* @return The tag for the biometrics. There may be multiple instances of a biometric within.
@@ -73,10 +75,40 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
*/
protected abstract ArrayList<T> getCopy(ArrayList<T> array);
protected abstract void doWriteState(@NonNull TypedXmlSerializer serializer) throws Exception;
/**
* @return Writes the cached data to persistent storage.
* @Writes the cached data to persistent storage.
*/
protected abstract void doWriteState();
private void doWriteStateInternal() {
AtomicFile destination = new AtomicFile(mFile);
FileOutputStream out = null;
try {
out = destination.startWrite();
TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
// Store the authenticatorId
serializer.startTag(null, TAG_INVALIDATION);
serializer.attributeBoolean(null, ATTR_INVALIDATION, mInvalidationInProgress);
serializer.endTag(null, TAG_INVALIDATION);
// Do any additional serialization that subclasses may require
doWriteState(serializer);
serializer.endDocument();
destination.finishWrite(out);
} catch (Throwable t) {
Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
destination.failWrite(out);
throw new IllegalStateException("Failed to write to file: " + mFile.toString(), t);
} finally {
IoUtils.closeQuietly(out);
}
}
/**
* @return
@@ -93,6 +125,19 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
}
}
public void setInvalidationInProgress(boolean invalidationInProgress) {
synchronized (this) {
mInvalidationInProgress = invalidationInProgress;
scheduleWriteStateLocked();
}
}
public boolean isInvalidationInProgress() {
synchronized (this) {
return mInvalidationInProgress;
}
}
public void addBiometric(T identifier) {
synchronized (this) {
mBiometrics.add(identifier);
@@ -202,6 +247,8 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
String tagName = parser.getName();
if (tagName.equals(getBiometricsTag())) {
parseBiometricsLocked(parser);
} else if (tagName.equals(TAG_INVALIDATION)) {
mInvalidationInProgress = parser.getAttributeBoolean(null, ATTR_INVALIDATION);
}
}
}

View File

@@ -31,4 +31,6 @@ public interface BiometricUtils<T extends BiometricAuthenticator.Identifier> {
void removeBiometricForUser(Context context, int userId, int biometricId);
void renameBiometricForUser(Context context, int userId, int biometricId, CharSequence name);
CharSequence getUniqueName(Context context, int userId);
void setInvalidationInProgress(Context context, int userId, boolean inProgress);
boolean isInvalidationInProgress(Context context, int userId);
}

View File

@@ -105,8 +105,8 @@ public abstract class ClientMonitor<T> extends LoggableMonitor implements IBinde
public ClientMonitor(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@Nullable IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int cookie, int sensorId, int statsModality, int statsAction,
int statsClient, boolean shouldLogMetrics) {
super(statsModality, statsAction, statsClient, shouldLogMetrics);
int statsClient) {
super(statsModality, statsAction, statsClient);
mSequentialId = sCount++;
mContext = context;
mLazyDaemon = lazyDaemon;

View File

@@ -49,10 +49,10 @@ public abstract class EnrollClient<T> extends AcquisitionClient<T> {
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull byte[] hardwareAuthToken, @NonNull String owner, @NonNull BiometricUtils utils,
int timeoutSec, int statsModality, int sensorId,
boolean shouldVibrate, boolean shouldLogMetrics) {
boolean shouldVibrate) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
statsModality, BiometricsProtoEnums.ACTION_ENROLL,
BiometricsProtoEnums.CLIENT_UNKNOWN, shouldLogMetrics);
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;

View File

@@ -32,7 +32,7 @@ public abstract class GenerateChallengeClient<T> extends ClientMonitor<T> {
@NonNull String owner, int sensorId) {
super(context, lazyDaemon, token, listener, 0 /* userId */, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@Override

View File

@@ -107,8 +107,7 @@ public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Ide
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* ClientMonitorCallbackConverter */,
userId, owner, 0 /* cookie */, sensorId, statsModality,
BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_ENUMERATE, BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList;

View File

@@ -51,7 +51,7 @@ public abstract class InternalEnumerateClient<T> extends ClientMonitor<T>
// is all done internally.
super(context, lazyDaemon, token, null /* ClientMonitorCallbackConverter */, userId, owner,
0 /* cookie */, sensorId, statsModality, BiometricsProtoEnums.ACTION_ENUMERATE,
BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
BiometricsProtoEnums.CLIENT_UNKNOWN);
mEnrolledList = enrolledList;
mUtils = utils;
}

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;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricsProtoEnums;
/**
* ClientMonitor subclass for requesting authenticatorId invalidation. See
* {@link InvalidationRequesterClient} for more info.
*/
public abstract class InvalidationClient<S extends BiometricAuthenticator.Identifier, T>
extends ClientMonitor<T> {
private final BiometricUtils<S> mUtils;
public InvalidationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
int userId, int sensorId, @NonNull BiometricUtils<S> utils) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId,
context.getOpPackageName(), 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mUtils = utils;
}
public void onAuthenticatorIdInvalidated(long newAuthenticatorId) {
// TODO: Update framework w/ newAuthenticatorId
mCallback.onClientFinished(this, true /* success */);
}
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
startHalOperation();
}
@Override
public void unableToStart() {
}
}

View File

@@ -0,0 +1,86 @@
/*
* 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;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricsProtoEnums;
/**
* ClientMonitor subclass responsible for coordination of authenticatorId invalidation of other
* sensors. See {@link InvalidationClient} for the ClientMonitor subclass responsible for initiating
* the invalidation with individual HALs. AuthenticatorId invalidation is required on devices with
* multiple strong biometric sensors.
*
* The public Keystore and Biometric APIs are biometric-tied, not modality-tied, meaning that keys
* are unlockable by "any/all strong biometrics on the device", and not "only a specific strong
* sensor". The Keystore API allows for creation of biometric-tied keys that are invalidated upon
* new biometric enrollment. See
* {@link android.security.keystore.KeyGenParameterSpec.Builder#setInvalidatedByBiometricEnrollment}
*
* This has been supported on single-sensor devices by the various getAuthenticatorId APIs on the
* HIDL and AIDL biometric HAL interfaces, where:
* 1) authenticatorId is requested and stored during key generation
* 2) authenticatorId is contained within the HAT when biometric authentication succeeds
* 3) authenticatorId is automatically changed (below the framework) whenever a new biometric
* enrollment occurs.
*
* For multi-biometric devices, this will be done the following way:
* 1) New enrollment added for Sensor1. Sensor1's HAL/TEE updates its authenticatorId automatically
* when enrollment completes
* 2) Framework marks Sensor1 as "invalidationInProgress". See
* {@link BiometricUtils#setInvalidationInProgress(Context, int, boolean)}
* 3) After all other sensors have finished invalidation, the framework will clear the invalidation
* flag for Sensor1.
* 4) New keys that are generated will include all new authenticatorIds
*
* The above is robust to incomplete invalidation. For example, when system boots or after user
* switches, the framework can check if any sensor has the "invalidationInProgress" flag set. If so,
* the framework should re-start the invalidation process described above.
*/
public abstract class InvalidationRequesterClient<T> extends ClientMonitor<T> {
private final BiometricManager mBiometricManager;
public InvalidationRequesterClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
int userId, int sensorId) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId,
context.getOpPackageName(), 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricManager = context.getSystemService(BiometricManager.class);
}
@Override
public void start(@NonNull Callback callback) {
super.start(callback);
// TODO(b/159667191): Request BiometricManager/BiometricService to invalidate
// authenticatorIds. Be sure to invoke BiometricUtils#setInvalidationInProgress(true)
}
@Override
public void unableToStart() {
}
@Override
protected void startHalOperation() {
// No HAL operations necessary
}
}

View File

@@ -38,7 +38,7 @@ public abstract class LoggableMonitor {
private final int mStatsAction;
private final int mStatsClient;
private long mFirstAcquireTimeMs;
private boolean mShouldLogMetrics;
private boolean mShouldLogMetrics = true;
/**
* Only valid for AuthenticationClient.
@@ -52,14 +52,15 @@ public abstract class LoggableMonitor {
* @param statsModality One of {@link BiometricsProtoEnums} MODALITY_* constants.
* @param statsAction One of {@link BiometricsProtoEnums} ACTION_* constants.
* @param statsClient One of {@link BiometricsProtoEnums} CLIENT_* constants.
* @param shouldLogMetrics If set to false, metrics will not be reported to statsd.
*/
public LoggableMonitor(int statsModality, int statsAction, int statsClient,
boolean shouldLogMetrics) {
public LoggableMonitor(int statsModality, int statsAction, int statsClient) {
mStatsModality = statsModality;
mStatsAction = statsAction;
mStatsClient = statsClient;
mShouldLogMetrics = shouldLogMetrics;
}
protected void setShouldLog(boolean shouldLog) {
mShouldLogMetrics = shouldLog;
}
public int getStatsClient() {

View File

@@ -45,7 +45,7 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,
int sensorId, @NonNull Map<Integer, Long> authenticatorIds, int statsModality) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
statsModality, BiometricsProtoEnums.ACTION_REMOVE,
BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricId = biometricId;
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;

View File

@@ -27,8 +27,7 @@ public abstract class RevokeChallengeClient<T> extends ClientMonitor<T> {
@NonNull IBinder token, @NonNull String owner, int sensorId) {
super(context, lazyDaemon, token, null /* listener */, 0 /* userId */, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
}
@Override

View File

@@ -16,23 +16,18 @@
package com.android.server.biometrics.sensors.face;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.face.Face;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.server.biometrics.sensors.BiometricUserState;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -75,46 +70,26 @@ public class FaceUserState extends BiometricUserState<Face> {
}
@Override
protected void doWriteState() {
AtomicFile destination = new AtomicFile(mFile);
ArrayList<Face> faces;
protected void doWriteState(@NonNull TypedXmlSerializer serializer) throws Exception {
final ArrayList<Face> faces;
synchronized (this) {
faces = getCopy(mBiometrics);
}
FileOutputStream out = null;
try {
out = destination.startWrite();
serializer.startTag(null, TAG_FACES);
TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_FACES);
final int count = faces.size();
for (int i = 0; i < count; i++) {
Face f = faces.get(i);
serializer.startTag(null, TAG_FACE);
serializer.attributeInt(null, ATTR_FACE_ID, f.getBiometricId());
serializer.attribute(null, ATTR_NAME, f.getName().toString());
serializer.attributeLong(null, ATTR_DEVICE_ID, f.getDeviceId());
serializer.endTag(null, TAG_FACE);
}
serializer.endTag(null, TAG_FACES);
serializer.endDocument();
destination.finishWrite(out);
// Any error while writing is fatal.
} catch (Throwable t) {
Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
destination.failWrite(out);
throw new IllegalStateException("Failed to write faces", t);
} finally {
IoUtils.closeQuietly(out);
final int count = faces.size();
for (int i = 0; i < count; i++) {
Face f = faces.get(i);
serializer.startTag(null, TAG_FACE);
serializer.attributeInt(null, ATTR_FACE_ID, f.getBiometricId());
serializer.attribute(null, ATTR_NAME, f.getName().toString());
serializer.attributeLong(null, ATTR_DEVICE_ID, f.getDeviceId());
serializer.endTag(null, TAG_FACE);
}
serializer.endTag(null, TAG_FACES);
}
@GuardedBy("this")

View File

@@ -18,7 +18,6 @@ package com.android.server.biometrics.sensors.face;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.face.Face;
import android.text.TextUtils;
import android.util.SparseArray;
@@ -115,6 +114,16 @@ public class FaceUtils implements BiometricUtils<Face> {
return getStateForUser(context, userId).getUniqueName();
}
@Override
public void setInvalidationInProgress(Context context, int userId, boolean inProgress) {
getStateForUser(context, userId).setInvalidationInProgress(inProgress);
}
@Override
public boolean isInvalidationInProgress(Context context, int userId) {
return getStateForUser(context, userId).isInvalidationInProgress();
}
private FaceUserState getStateForUser(Context ctx, int userId) {
synchronized (this) {
FaceUserState state = mUserStates.get(userId);

View File

@@ -62,7 +62,7 @@ public class FaceEnrollClient extends EnrollClient<ISession> {
@Nullable NativeHandle previewSurface, int sensorId, int maxTemplatesPerUser) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, opPackageName, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
false /* shouldVibrate */, true /* shouldLogMetrics */);
false /* shouldVibrate */);
mEnrollIgnoreList = getContext().getResources()
.getIntArray(R.array.config_face_acquire_enroll_ignorelist);
mEnrollIgnoreListVendor = getContext().getResources()

View File

@@ -38,8 +38,7 @@ class FaceGetAuthenticatorIdClient extends ClientMonitor<ISession> {
Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, opPackageName,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FACE,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mAuthenticatorIds = authenticatorIds;
}

View File

@@ -0,0 +1,48 @@
/*
* 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.content.Context;
import android.hardware.biometrics.face.ISession;
import android.annotation.NonNull;
import android.hardware.face.Face;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.InvalidationClient;
import com.android.server.biometrics.sensors.face.FaceUtils;
public class FaceInvalidationClient extends InvalidationClient<Face, ISession> {
private static final String TAG = "FaceInvalidationClient";
public FaceInvalidationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, int userId, int sensorId,
@NonNull FaceUtils utils) {
super(context, lazyDaemon, userId, sensorId, utils);
}
@Override
protected void startHalOperation() {
try {
getFreshDaemon().invalidateAuthenticatorId(mSequentialId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -50,8 +50,7 @@ public class FaceResetLockoutClient extends ClientMonitor<ISession> {
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;

View File

@@ -59,7 +59,7 @@ public class FaceEnrollClient extends EnrollClient<IBiometricsFace> {
@Nullable NativeHandle surfaceHandle, int sensorId) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FACE, sensorId,
false /* shouldVibrate */, true /* shouldLogMetrics */);
false /* shouldVibrate */);
mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length);
mSurfaceHandle = surfaceHandle;
mEnrollIgnoreList = getContext().getResources()

View File

@@ -47,7 +47,7 @@ public class FaceGetFeatureClient extends ClientMonitor<IBiometricsFace> {
@NonNull String owner, int sensorId, int feature, int faceId) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
mFaceId = faceId;

View File

@@ -42,8 +42,7 @@ public class FaceResetLockoutClient extends ClientMonitor<IBiometricsFace> {
@NonNull byte[] hardwareAuthToken) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mHardwareAuthToken = new ArrayList<>();
for (byte b : hardwareAuthToken) {

View File

@@ -49,7 +49,7 @@ public class FaceSetFeatureClient extends ClientMonitor<IBiometricsFace> {
byte[] hardwareAuthToken, int faceId) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_UNKNOWN, BiometricsProtoEnums.ACTION_UNKNOWN,
BiometricsProtoEnums.CLIENT_UNKNOWN, true /* shouldLogMetrics */);
BiometricsProtoEnums.CLIENT_UNKNOWN);
mFeature = feature;
mEnabled = enabled;
mFaceId = faceId;

View File

@@ -43,8 +43,7 @@ public class FaceUpdateActiveUserClient extends ClientMonitor<IBiometricsFace> {
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mCurrentUserId = currentUserId;
mHasEnrolledBiometrics = hasEnrolledBIometrics;
mAuthenticatorIds = authenticatorIds;

View File

@@ -16,23 +16,18 @@
package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.fingerprint.Fingerprint;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.server.biometrics.sensors.BiometricUserState;
import libcore.io.IoUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
@@ -76,47 +71,27 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
}
@Override
protected void doWriteState() {
AtomicFile destination = new AtomicFile(mFile);
ArrayList<Fingerprint> fingerprints;
protected void doWriteState(@NonNull TypedXmlSerializer serializer) throws Exception {
final ArrayList<Fingerprint> fingerprints;
synchronized (this) {
fingerprints = getCopy(mBiometrics);
}
FileOutputStream out = null;
try {
out = destination.startWrite();
serializer.startTag(null, TAG_FINGERPRINTS);
TypedXmlSerializer serializer = Xml.resolveSerializer(out);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
serializer.startTag(null, TAG_FINGERPRINTS);
final int count = fingerprints.size();
for (int i = 0; i < count; i++) {
Fingerprint fp = fingerprints.get(i);
serializer.startTag(null, TAG_FINGERPRINT);
serializer.attributeInt(null, ATTR_FINGER_ID, fp.getBiometricId());
serializer.attribute(null, ATTR_NAME, fp.getName().toString());
serializer.attributeInt(null, ATTR_GROUP_ID, fp.getGroupId());
serializer.attributeLong(null, ATTR_DEVICE_ID, fp.getDeviceId());
serializer.endTag(null, TAG_FINGERPRINT);
}
serializer.endTag(null, TAG_FINGERPRINTS);
serializer.endDocument();
destination.finishWrite(out);
// Any error while writing is fatal.
} catch (Throwable t) {
Slog.wtf(TAG, "Failed to write settings, restoring backup", t);
destination.failWrite(out);
throw new IllegalStateException("Failed to write fingerprints", t);
} finally {
IoUtils.closeQuietly(out);
final int count = fingerprints.size();
for (int i = 0; i < count; i++) {
Fingerprint fp = fingerprints.get(i);
serializer.startTag(null, TAG_FINGERPRINT);
serializer.attributeInt(null, ATTR_FINGER_ID, fp.getBiometricId());
serializer.attribute(null, ATTR_NAME, fp.getName().toString());
serializer.attributeInt(null, ATTR_GROUP_ID, fp.getGroupId());
serializer.attributeLong(null, ATTR_DEVICE_ID, fp.getDeviceId());
serializer.endTag(null, TAG_FINGERPRINT);
}
serializer.endTag(null, TAG_FINGERPRINTS);
}
@GuardedBy("this")

View File

@@ -118,6 +118,16 @@ public class FingerprintUtils implements BiometricUtils<Fingerprint> {
return getStateForUser(context, userId).getUniqueName();
}
@Override
public void setInvalidationInProgress(Context context, int userId, boolean inProgress) {
getStateForUser(context, userId).setInvalidationInProgress(inProgress);
}
@Override
public boolean isInvalidationInProgress(Context context, int userId) {
return getStateForUser(context, userId).isInvalidationInProgress();
}
private FingerprintUserState getStateForUser(Context ctx, int userId) {
synchronized (this) {
FingerprintUserState state = mUserStates.get(userId);

View File

@@ -51,7 +51,7 @@ class FingerprintDetectClient extends AcquisitionClient<ISession> {
int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
statsClient, true /* shouldLogMetrics */);
statsClient);
mIsStrongBiometric = isStrongBiometric;
mUdfpsOverlayController = udfpsOverlayController;
}

View File

@@ -55,9 +55,10 @@ class FingerprintEnrollClient extends EnrollClient<ISession> implements Udfps {
boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
0 /* timeoutSec */, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
true /* shouldVibrate */, shouldLogMetrics);
true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOvelayController;
mMaxTemplatesPerUser = maxTemplatesPerUser;
setShouldLog(shouldLogMetrics);
}
@Override

View File

@@ -38,8 +38,7 @@ class FingerprintGetAuthenticatorIdClient extends ClientMonitor<ISession> {
int sensorId, Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mAuthenticatorIds = authenticatorIds;
}

View File

@@ -0,0 +1,47 @@
/*
* 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.content.Context;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.fingerprint.Fingerprint;
import android.os.RemoteException;
import android.util.Slog;
import com.android.server.biometrics.sensors.InvalidationClient;
import com.android.server.biometrics.sensors.fingerprint.FingerprintUtils;
public class FingerprintInvalidationClient extends InvalidationClient<Fingerprint, ISession> {
private static final String TAG = "FingerprintInvalidationClient";
public FingerprintInvalidationClient(@NonNull Context context,
@NonNull LazyDaemon<ISession> lazyDaemon, int userId, int sensorId,
@NonNull FingerprintUtils utils) {
super(context, lazyDaemon, userId, sensorId, utils);
}
@Override
protected void startHalOperation() {
try {
getFreshDaemon().invalidateAuthenticatorId(mSequentialId);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
mCallback.onClientFinished(this, false /* success */);
}
}
}

View File

@@ -50,8 +50,7 @@ class FingerprintResetLockoutClient extends ClientMonitor<ISession> {
@NonNull LockoutResetDispatcher lockoutResetDispatcher) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mHardwareAuthToken = HardwareAuthTokenUtils.toHardwareAuthToken(hardwareAuthToken);
mLockoutCache = lockoutTracker;
mLockoutResetDispatcher = lockoutResetDispatcher;

View File

@@ -56,7 +56,7 @@ class FingerprintDetectClient extends AcquisitionClient<IBiometricsFingerprint>
boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
BiometricsProtoEnums.MODALITY_FINGERPRINT, BiometricsProtoEnums.ACTION_AUTHENTICATE,
statsClient, true /* shouldLogMetrics */);
statsClient);
mUdfpsOverlayController = udfpsOverlayController;
mIsStrongBiometric = isStrongBiometric;
}

View File

@@ -56,8 +56,9 @@ public class FingerprintEnrollClient extends EnrollClient<IBiometricsFingerprint
boolean shouldLogMetrics) {
super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils,
timeoutSec, BiometricsProtoEnums.MODALITY_FINGERPRINT, sensorId,
true /* shouldVibrate */, shouldLogMetrics);
true /* shouldVibrate */);
mUdfpsOverlayController = udfpsOverlayController;
setShouldLog(shouldLogMetrics);
}
@Override

View File

@@ -50,8 +50,7 @@ public class FingerprintUpdateActiveUserClient extends ClientMonitor<IBiometrics
@NonNull Map<Integer, Long> authenticatorIds) {
super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner,
0 /* cookie */, sensorId, BiometricsProtoEnums.MODALITY_UNKNOWN,
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN,
true /* shouldLogMetrics */);
BiometricsProtoEnums.ACTION_UNKNOWN, BiometricsProtoEnums.CLIENT_UNKNOWN);
mCurrentUserId = currentUserId;
mHasEnrolledBiometrics = hasEnrolledBiometrics;
mAuthenticatorIds = authenticatorIds;

View File

@@ -218,7 +218,7 @@ public class BiometricSchedulerTest {
@NonNull LazyDaemon<Object> lazyDaemon, int cookie) {
super(context, lazyDaemon, token /* token */, null /* listener */, 0 /* userId */,
TAG, cookie, TEST_SENSOR_ID, 0 /* statsModality */,
0 /* statsAction */, 0 /* statsClient */, true /* shouldLogMetrics */);
0 /* statsAction */, 0 /* statsClient */);
}