8/n: Update biometric utils to have sensorId-specific files

New HAL interfaces have a strongly defined notion of sensorId whereas
existing interfaces do not. This change does the following:

1) FingerprintUtils/FaceUtils is updated to contain singleton
   instances for each sensorId. The retrieved instance is still
   a utility class for a single sensor
2) Existing devices with old HALs will continue to use
   settings_fingerprint.xml and settings_face.xml
3) Devices with new HALs will use sensorId-specific files, e.g.
   on a device where the fingerprint sensorId=0 and face sensorId=1,
   the below files will be used:
   settings_fingerprint_0.xml, settings_face_1.xml
4) Updated existing AIDL provider to use sensor-specific utils

Bug: 170497736
Test: Enrollments on existing devices not affected

Change-Id: I5c48ab927d0450820f165707d60e0710e86be5e4
This commit is contained in:
Kevin Chyn
2020-10-14 12:08:43 -07:00
parent ac6fe81d05
commit 3a3e22409a
8 changed files with 114 additions and 56 deletions

View File

@@ -16,6 +16,7 @@
package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.os.AsyncTask;
@@ -61,11 +62,6 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
*/
protected abstract String getBiometricsTag();
/**
* @return The file where the biometric metadata should be stored.
*/
protected abstract String getBiometricFile();
/**
* @return The resource for the name template, this is used to generate the default name.
*/
@@ -88,8 +84,8 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
throws IOException, XmlPullParserException;
public BiometricUserState(Context context, int userId) {
mFile = getFileForUser(userId);
public BiometricUserState(Context context, int userId, @NonNull String fileName) {
mFile = getFileForUser(userId, fileName);
mContext = context;
synchronized (this) {
readStateSyncLocked();
@@ -159,8 +155,8 @@ public abstract class BiometricUserState<T extends BiometricAuthenticator.Identi
return true;
}
private File getFileForUser(int userId) {
return new File(Environment.getUserSystemDirectory(userId), getBiometricFile());
private File getFileForUser(int userId, @NonNull String fileName) {
return new File(Environment.getUserSystemDirectory(userId), fileName);
}
private void scheduleWriteStateLocked() {

View File

@@ -43,7 +43,6 @@ import java.util.ArrayList;
public class FaceUserState extends BiometricUserState<Face> {
private static final String TAG = "FaceState";
private static final String FACE_FILE = "settings_face.xml";
private static final String TAG_FACES = "faces";
private static final String TAG_FACE = "face";
@@ -51,8 +50,8 @@ public class FaceUserState extends BiometricUserState<Face> {
private static final String ATTR_FACE_ID = "faceId";
private static final String ATTR_DEVICE_ID = "deviceId";
public FaceUserState(Context ctx, int userId) {
super(ctx, userId);
public FaceUserState(Context ctx, int userId, String fileName) {
super(ctx, userId, fileName);
}
@Override
@@ -60,11 +59,6 @@ public class FaceUserState extends BiometricUserState<Face> {
return TAG_FACES;
}
@Override
protected String getBiometricFile() {
return FACE_FILE;
}
@Override
protected int getNameTemplateResource() {
return com.android.internal.R.string.face_name_template;

View File

@@ -16,6 +16,7 @@
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;
@@ -33,21 +34,56 @@ import java.util.List;
public class FaceUtils implements BiometricUtils<Face> {
private static final Object sInstanceLock = new Object();
private static FaceUtils sInstance;
// Map<SensorId, FaceUtils>
private static SparseArray<FaceUtils> sInstances;
private static final String LEGACY_FACE_FILE = "settings_face.xml";
@GuardedBy("this")
private final SparseArray<FaceUserState> mUsers = new SparseArray<>();
private final SparseArray<FaceUserState> mUserStates;
private final String mFileName;
public static FaceUtils getInstance() {
synchronized (sInstanceLock) {
if (sInstance == null) {
sInstance = new FaceUtils();
}
}
return sInstance;
public static FaceUtils getInstance(int sensorId) {
// Specify a null fileName to use an auto-generated sensorId-specific filename.
return getInstance(sensorId, null /* fileName */);
}
private FaceUtils() {
/**
* Retrieves an instance for the specified sensorId. If the fileName is null, a default
* filename (e.g. settings_face_<sensorId>.xml will be generated.
*
* Specifying an explicit fileName allows for backward compatibility with legacy devices,
* where everything is stored in settings_face.xml.
*/
private static FaceUtils getInstance(int sensorId, @Nullable String fileName) {
final FaceUtils utils;
synchronized (sInstanceLock) {
if (sInstances == null) {
sInstances = new SparseArray<>();
}
if (sInstances.get(sensorId) == null) {
if (fileName == null) {
fileName = "settings_face_" + sensorId + ".xml";
}
sInstances.put(sensorId, new FaceUtils(fileName));
}
utils = sInstances.get(sensorId);
}
return utils;
}
/**
* Legacy getter for {@link android.hardware.biometrics.face.V1_0} and its extended subclasses,
* which do not support a well defined sensorId from the HAL.
*/
public static FaceUtils getInstance() {
// Note that sensorId for legacy services can be hard-coded to 0 since it's only used
// to index into the sensor states map.
return getInstance(0 /* sensorId */, LEGACY_FACE_FILE);
}
private FaceUtils(String fileName) {
mUserStates = new SparseArray<>();
mFileName = fileName;
}
@Override
@@ -81,10 +117,10 @@ public class FaceUtils implements BiometricUtils<Face> {
private FaceUserState getStateForUser(Context ctx, int userId) {
synchronized (this) {
FaceUserState state = mUsers.get(userId);
FaceUserState state = mUserStates.get(userId);
if (state == null) {
state = new FaceUserState(ctx, userId);
mUsers.put(userId, state);
state = new FaceUserState(ctx, userId, mFileName);
mUserStates.put(userId, state);
}
return state;
}

View File

@@ -42,7 +42,6 @@ import java.util.ArrayList;
public class FingerprintUserState extends BiometricUserState<Fingerprint> {
private static final String TAG = "FingerprintState";
private static final String FINGERPRINT_FILE = "settings_fingerprint.xml";
private static final String TAG_FINGERPRINTS = "fingerprints";
private static final String TAG_FINGERPRINT = "fingerprint";
@@ -51,8 +50,8 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
private static final String ATTR_FINGER_ID = "fingerId";
private static final String ATTR_DEVICE_ID = "deviceId";
public FingerprintUserState(Context context, int userId) {
super(context, userId);
public FingerprintUserState(Context context, int userId, String fileName) {
super(context, userId, fileName);
}
@Override
@@ -60,11 +59,6 @@ public class FingerprintUserState extends BiometricUserState<Fingerprint> {
return TAG_FINGERPRINTS;
}
@Override
protected String getBiometricFile() {
return FINGERPRINT_FILE;
}
@Override
protected int getNameTemplateResource() {
return com.android.internal.R.string.fingerprint_name_template;

View File

@@ -16,8 +16,8 @@
package com.android.server.biometrics.sensors.fingerprint;
import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.fingerprint.Fingerprint;
import android.text.TextUtils;
import android.util.SparseArray;
@@ -33,21 +33,59 @@ import java.util.List;
public class FingerprintUtils implements BiometricUtils<Fingerprint> {
private static final Object sInstanceLock = new Object();
private static FingerprintUtils sInstance;
// Map<SensorId, FingerprintUtils>
private static SparseArray<FingerprintUtils> sInstances;
private static final String LEGACY_FINGERPRINT_FILE = "settings_fingerprint.xml";
@GuardedBy("this")
private final SparseArray<FingerprintUserState> mUsers = new SparseArray<>();
private final SparseArray<FingerprintUserState> mUserStates;
private final String mFileName;
public static FingerprintUtils getInstance() {
synchronized (sInstanceLock) {
if (sInstance == null) {
sInstance = new FingerprintUtils();
}
}
return sInstance;
/**
* Retrieves an instance for the specified sensorId.
*/
public static FingerprintUtils getInstance(int sensorId) {
// Specify a null fileName to use an auto-generated sensorId-specific filename.
return getInstance(sensorId, null /* fileName */);
}
private FingerprintUtils() {
/**
* Retrieves an instance for the specified sensorId. If the fileName is null, a default
* filename (e.g. settings_fingerprint_<sensorId>.xml will be generated.
*
* Specifying an explicit fileName allows for backward compatibility with legacy devices,
* where everything is stored in settings_fingerprint.xml.
*/
private static FingerprintUtils getInstance(int sensorId, @Nullable String fileName) {
final FingerprintUtils utils;
synchronized (sInstanceLock) {
if (sInstances == null) {
sInstances = new SparseArray<>();
}
if (sInstances.get(sensorId) == null) {
if (fileName == null) {
fileName = "settings_fingerprint_" + sensorId + ".xml";
}
sInstances.put(sensorId, new FingerprintUtils(fileName));
}
utils = sInstances.get(sensorId);
}
return utils;
}
/**
* Legacy getter for {@link android.hardware.biometrics.fingerprint.V2_1} ands its extended
* subclasses, which do not support a well defined sensorId from the HAL.
*/
public static FingerprintUtils getInstance() {
// Note that sensorId for legacy services can be hard-coded to 0 since it's only used
// to index into the sensor states map.
return getInstance(0 /* sensorId */, LEGACY_FINGERPRINT_FILE);
}
private FingerprintUtils(String fileName) {
mUserStates = new SparseArray<>();
mFileName = fileName;
}
@Override
@@ -82,10 +120,10 @@ public class FingerprintUtils implements BiometricUtils<Fingerprint> {
private FingerprintUserState getStateForUser(Context ctx, int userId) {
synchronized (this) {
FingerprintUserState state = mUsers.get(userId);
FingerprintUserState state = mUserStates.get(userId);
if (state == null) {
state = new FingerprintUserState(ctx, userId);
mUsers.put(userId, state);
state = new FingerprintUserState(ctx, userId, mFileName);
mUserStates.put(userId, state);
}
return state;
}

View File

@@ -61,7 +61,7 @@ public class FingerprintEnrollClient extends EnrollClient<ISession> implements U
@Override
protected boolean hasReachedEnrollmentLimit() {
return FingerprintUtils.getInstance()
return FingerprintUtils.getInstance(getSensorId())
.getBiometricsForUser(getContext(), getTargetUserId()).size()
>= mMaxTemplatesPerUser;
}

View File

@@ -285,7 +285,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final FingerprintEnrollClient client = new FingerprintEnrollClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken,
opPackageName, FingerprintUtils.getInstance(), sensorId,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
mUdfpsOverlayController, maxTemplatesPerUser);
scheduleForSensor(sensorId, client, new ClientMonitor.Callback() {
@Override
@@ -380,7 +380,7 @@ public class FingerprintProvider implements IBinder.DeathRecipient, ServiceProvi
final FingerprintRemovalClient client = new FingerprintRemovalClient(mContext,
mSensors.get(sensorId).getLazySession(), token,
new ClientMonitorCallbackConverter(receiver), fingerId, userId,
opPackageName, FingerprintUtils.getInstance(), sensorId,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
mSensors.get(sensorId).getAuthenticatorIds());
mSensors.get(sensorId).getScheduler().scheduleClientMonitor(client);
} catch (RemoteException e) {

View File

@@ -162,7 +162,7 @@ class Sensor {
}
final int currentUserId = client.getTargetUserId();
final CharSequence name = FingerprintUtils.getInstance()
final CharSequence name = FingerprintUtils.getInstance(sensorId)
.getUniqueName(mContext, currentUserId);
final Fingerprint fingerprint = new Fingerprint(name, enrollmentId, sensorId);