Merge "1/n: Add ClientMonitors for authenticatorId invalidation"
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user