3
0
Fork 0

Face VHAL for user build

Bug: 326227403

Test: atest android.hardware.biometrics.face.* -c
Test: atest CtsBiometricsTestCases -c
Flag: TEST_ONLY
Change-Id: I869b68eba81166aacfc2a8a35c303940722214f3
This commit is contained in:
Jeff Pu 2024-09-10 12:52:22 +00:00
parent d014c14c78
commit 7b3dcebe63
7 changed files with 189 additions and 23 deletions

View File

@ -99,6 +99,7 @@ filegroup {
":android.hardware.biometrics.common-V4-java-source",
":android.hardware.biometrics.fingerprint-V5-java-source",
":android.hardware.biometrics.fingerprint.virtualhal-java-source",
":android.hardware.biometrics.face.virtualhal-java-source",
":android.hardware.biometrics.face-V4-java-source",
":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",

View File

@ -22,6 +22,7 @@ import android.annotation.Nullable;
import android.content.Context;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.biometrics.face.virtualhal.IVirtualHal;
import android.os.Binder;
import android.os.Parcel;
import android.os.Parcelable;
@ -160,6 +161,41 @@ public class FaceSensorConfigurations implements Parcelable {
dest.writeByte((byte) (mResetLockoutRequiresChallenge ? 1 : 0));
dest.writeMap(mSensorPropsMap);
}
/**
* Remap fqName of VHAL because the `virtual` instance is registered
* with IVirtulalHal now (IFace previously)
* @param fqName fqName to be translated
* @return real fqName
*/
public static String remapFqName(String fqName) {
if (!fqName.contains(IFace.DESCRIPTOR + "/virtual")) {
return fqName; //no remap needed for real hardware HAL
} else {
//new Vhal instance name
return fqName.replace("IFace", "virtualhal.IVirtualHal");
}
}
/**
* @param fqName aidl interface instance name
* @return aidl interface
*/
public static IFace getIFace(String fqName) {
if (fqName.contains("virtual")) {
String fqNameMapped = remapFqName(fqName);
Slog.i(TAG, "getIFace fqName is mapped: " + fqName + "->" + fqNameMapped);
try {
IVirtualHal vhal = IVirtualHal.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForService(fqNameMapped)));
return vhal.getFaceHal();
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in vhal.getFaceHal() call" + fqNameMapped);
}
}
return IFace.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));
}
/**
* Returns face sensor props for the HAL {@param instance}.
@ -173,14 +209,13 @@ public class FaceSensorConfigurations implements Parcelable {
return props;
}
final String fqName = IFace.DESCRIPTOR + "/" + instance;
IFace face = IFace.Stub.asInterface(Binder.allowBlocking(
ServiceManager.waitForDeclaredService(fqName)));
try {
if (face != null) {
props = face.getSensorProps();
final String fqName = IFace.DESCRIPTOR + "/" + instance;
final IFace fp = getIFace(fqName);
if (fp != null) {
props = fp.getSensorProps();
} else {
Slog.e(TAG, "Unable to get declared service: " + fqName);
Log.d(TAG, "IFace null for instance " + instance);
}
} catch (RemoteException e) {
Log.d(TAG, "Unable to get sensor properties!");

View File

@ -49,7 +49,6 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorLocationInternal;
import android.hardware.biometrics.SensorPropertiesInternal;
import android.hardware.biometrics.face.IFace;
import android.hardware.face.FaceSensorConfigurations;
import android.hardware.face.FaceSensorProperties;
import android.hardware.face.FaceSensorPropertiesInternal;
@ -73,6 +72,7 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.server.SystemService;
import com.android.server.biometrics.sensors.face.FaceService;
import com.android.server.biometrics.sensors.fingerprint.FingerprintService;
import com.android.server.companion.virtual.VirtualDeviceManagerInternal;
@ -211,7 +211,7 @@ public class AuthService extends SystemService {
*/
@VisibleForTesting
public String[] getFaceAidlInstances() {
return ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
return FaceService.getDeclaredInstances();
}
/**

View File

@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors.face;
import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FACE;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.hardware.face.FaceSensorConfigurations.getIFace;
import android.annotation.NonNull;
import android.annotation.Nullable;
@ -60,6 +61,7 @@ import android.util.proto.ProtoOutputStream;
import android.view.Surface;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
@ -753,7 +755,7 @@ public class FaceService extends SystemService {
public FaceService(Context context) {
this(context, null /* faceProviderFunction */, () -> IBiometricService.Stub.asInterface(
ServiceManager.getService(Context.BIOMETRIC_SERVICE)), null /* faceProvider */,
() -> ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR));
() -> getDeclaredInstances());
}
@VisibleForTesting FaceService(Context context,
@ -778,8 +780,7 @@ public class FaceService extends SystemService {
mFaceProvider = faceProvider != null ? faceProvider : (name) -> {
final String fqName = IFace.DESCRIPTOR + "/" + name;
final IFace face = IFace.Stub.asInterface(
Binder.allowBlocking(ServiceManager.waitForDeclaredService(fqName)));
final IFace face = getIFace(fqName);
if (face == null) {
Slog.e(TAG, "Unable to get declared service: " + fqName);
return null;
@ -835,6 +836,23 @@ public class FaceService extends SystemService {
*/
public static native void releaseSurfaceHandle(@NonNull NativeHandle handle);
/**
* Get all face hal instances declared in manifest
* @return instance names
*/
public static String[] getDeclaredInstances() {
String[] a = ServiceManager.getDeclaredInstances(IFace.DESCRIPTOR);
Slog.i(TAG, "Before:getDeclaredInstances: IFace instance found, a.length="
+ a.length);
if (!ArrayUtils.contains(a, "virtual")) {
// Now, the virtual hal is registered with IVirtualHal interface and it is also
// moved from vendor to system_ext partition without a device manifest. So
// if the old vhal is not declared, add here.
a = ArrayUtils.appendElement(String.class, a, "virtual");
}
Slog.i(TAG, "After:getDeclaredInstances: a.length=" + a.length);
return a;
}
void syncEnrollmentsNow() {
Utils.checkPermissionOrShell(getContext(), MANAGE_FACE);

View File

@ -23,6 +23,9 @@ import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.face.AuthenticationFrame;
import android.hardware.biometrics.face.BaseFrame;
import android.hardware.biometrics.face.EnrollmentFrame;
import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
import android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep;
import android.hardware.biometrics.face.virtualhal.NextEnrollment;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticationFrame;
import android.hardware.face.FaceEnrollFrame;
@ -50,6 +53,7 @@ import java.util.Set;
public class BiometricTestSessionImpl extends ITestSession.Stub {
private static final String TAG = "face/aidl/BiometricTestSessionImpl";
private static final int VHAL_ENROLLMENT_ID = 9999;
@NonNull private final Context mContext;
private final int mSensorId;
@ -144,16 +148,35 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
super.setTestHalEnabled_enforcePermission();
mProvider.setTestHalEnabled(enabled);
mSensor.setTestHalEnabled(enabled);
mProvider.setTestHalEnabled(enabled);
}
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public void startEnroll(int userId) {
public void startEnroll(int userId) throws RemoteException {
super.startEnroll_enforcePermission();
Slog.i(TAG, "startEnroll(): isVhalForTesting=" + mProvider.isVhalForTesting());
if (mProvider.isVhalForTesting()) {
final AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes =
{new AcquiredInfoAndVendorCode()};
final EnrollmentProgressStep[] enrollmentProgressSteps =
{new EnrollmentProgressStep(), new EnrollmentProgressStep()};
enrollmentProgressSteps[0].durationMs = 100;
enrollmentProgressSteps[0].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes;
enrollmentProgressSteps[1].durationMs = 200;
enrollmentProgressSteps[1].acquiredInfoAndVendorCodes = acquiredInfoAndVendorCodes;
final NextEnrollment nextEnrollment = new NextEnrollment();
nextEnrollment.id = VHAL_ENROLLMENT_ID;
nextEnrollment.progressSteps = enrollmentProgressSteps;
nextEnrollment.result = true;
mProvider.getVhal().setNextEnrollment(nextEnrollment);
mProvider.getVhal().setOperationAuthenticateDuration(6000);
}
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
mContext.getOpPackageName(), new int[0] /* disabledFeatures */,
null /* previewSurface */, false /* debugConsent */,
@ -166,6 +189,10 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
super.finishEnroll_enforcePermission();
if (mProvider.isVhalForTesting()) {
return;
}
int nextRandomId = mRandom.nextInt();
while (mEnrollmentIds.contains(nextRandomId)) {
nextRandomId = mRandom.nextInt();
@ -178,11 +205,16 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public void acceptAuthentication(int userId) {
public void acceptAuthentication(int userId) throws RemoteException {
// Fake authentication with any of the existing faces
super.acceptAuthentication_enforcePermission();
if (mProvider.isVhalForTesting()) {
mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID);
return;
}
List<Face> faces = FaceUtils.getInstance(mSensorId)
.getBiometricsForUser(mContext, userId);
if (faces.isEmpty()) {
@ -196,10 +228,15 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public void rejectAuthentication(int userId) {
public void rejectAuthentication(int userId) throws RemoteException {
super.rejectAuthentication_enforcePermission();
if (mProvider.isVhalForTesting()) {
mProvider.getVhal().setEnrollmentHit(VHAL_ENROLLMENT_ID + 1);
return;
}
mSensor.getSessionForUser(userId).getHalSessionCallback().onAuthenticationFailed();
}
@ -236,11 +273,17 @@ public class BiometricTestSessionImpl extends ITestSession.Stub {
@android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC)
@Override
public void cleanupInternalState(int userId) {
public void cleanupInternalState(int userId) throws RemoteException {
super.cleanupInternalState_enforcePermission();
Slog.d(TAG, "cleanupInternalState: " + userId);
if (mProvider.isVhalForTesting()) {
Slog.i(TAG, "cleanup virtualhal configurations");
mProvider.getVhal().resetConfigurations(); //setEnrollments(new int[]{});
}
mProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {

View File

@ -16,6 +16,9 @@
package com.android.server.biometrics.sensors.face.aidl;
import static android.hardware.face.FaceSensorConfigurations.getIFace;
import static android.hardware.face.FaceSensorConfigurations.remapFqName;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@ -32,6 +35,7 @@ import android.hardware.biometrics.ITestSession;
import android.hardware.biometrics.ITestSessionCallback;
import android.hardware.biometrics.face.IFace;
import android.hardware.biometrics.face.SensorProps;
import android.hardware.biometrics.face.virtualhal.IVirtualHal;
import android.hardware.face.Face;
import android.hardware.face.FaceAuthenticateOptions;
import android.hardware.face.FaceEnrollOptions;
@ -54,6 +58,7 @@ import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver;
import com.android.server.biometrics.AuthenticationStatsCollector;
import com.android.server.biometrics.BiometricDanglingReceiver;
import com.android.server.biometrics.BiometricHandlerProvider;
import com.android.server.biometrics.Flags;
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
@ -130,6 +135,11 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
private AuthenticationStatsCollector mAuthenticationStatsCollector;
@Nullable
private IFace mDaemon;
@Nullable
private IVirtualHal mVhal;
@Nullable
private String mHalInstanceNameCurrent;
private final class BiometricTaskStackListener extends TaskStackListener {
@Override
@ -286,14 +296,37 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
if (mTestHalEnabled) {
return true;
}
return ServiceManager.checkService(IFace.DESCRIPTOR + "/" + mHalInstanceName) != null;
return ServiceManager.checkService(
remapFqName(IFace.DESCRIPTOR + "/" + mHalInstanceName)) != null;
}
@Nullable
@VisibleForTesting
synchronized IFace getHalInstance() {
if (mTestHalEnabled) {
return new TestHal();
if (Flags.useVhalForTesting()) {
if (!mHalInstanceNameCurrent.contains("virtual")) {
Slog.i(getTag(), "Switching face hal from " + mHalInstanceName
+ " to virtual hal");
mHalInstanceNameCurrent = "virtual";
mDaemon = null;
}
} else {
// Enabling the test HAL for a single sensor in a multi-sensor HAL currently enables
// the test HAL for all sensors under that HAL. This can be updated in the future if
// necessary.
return new TestHal();
}
} else {
if (mHalInstanceNameCurrent == null) {
mHalInstanceNameCurrent = mHalInstanceName;
} else if (mHalInstanceNameCurrent.contains("virtual")
&& mHalInstanceNameCurrent != mHalInstanceName) {
Slog.i(getTag(), "Switching face from virtual hal " + "to "
+ mHalInstanceName);
mHalInstanceNameCurrent = mHalInstanceName;
mDaemon = null;
}
}
if (mDaemon != null) {
@ -302,10 +335,7 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
Slog.d(getTag(), "Daemon was null, reconnecting");
mDaemon = IFace.Stub.asInterface(
Binder.allowBlocking(
ServiceManager.waitForDeclaredService(
IFace.DESCRIPTOR + "/" + mHalInstanceName)));
mDaemon = getIFace(IFace.DESCRIPTOR + "/" + mHalInstanceNameCurrent);
if (mDaemon == null) {
Slog.e(getTag(), "Unable to get daemon");
return null;
@ -833,7 +863,13 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
}
void setTestHalEnabled(boolean enabled) {
final boolean changed = enabled != mTestHalEnabled;
mTestHalEnabled = enabled;
Slog.i(getTag(), "setTestHalEnabled(): isVhalForTestingFlags=" + Flags.useVhalForTesting()
+ " mTestHalEnabled=" + mTestHalEnabled + " changed=" + changed);
if (changed && isVhalForTesting()) {
getHalInstance();
}
}
@Override
@ -850,10 +886,41 @@ public class FaceProvider implements IBinder.DeathRecipient, ServiceProvider {
return mTestHalEnabled;
}
/**
* Return true if vhal_for_testing feature is enabled and test is active
*/
public boolean isVhalForTesting() {
return (Flags.useVhalForTesting() && mTestHalEnabled);
}
/**
* Sends a face re enroll notification.
*/
public void sendFaceReEnrollNotification() {
mAuthenticationStatsCollector.sendFaceReEnrollNotification();
}
/**
* Sends a fingerprint enroll notification.
*/
public void sendFingerprintReEnrollNotification() {
mAuthenticationStatsCollector.sendFingerprintReEnrollNotification();
}
/**
* Return virtual hal AIDL interface if it is used for testing
*
*/
public IVirtualHal getVhal() throws RemoteException {
if (mVhal == null && isVhalForTesting()) {
mVhal = IVirtualHal.Stub.asInterface(
Binder.allowBlocking(
ServiceManager.waitForService(
IVirtualHal.DESCRIPTOR + "/"
+ mHalInstanceNameCurrent)));
Slog.d(getTag(), "getVhal " + mHalInstanceNameCurrent);
}
return mVhal;
}
}

View File

@ -17,6 +17,7 @@
package com.android.server.biometrics.sensors.face.aidl;
import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE;
import static android.hardware.face.FaceSensorConfigurations.remapFqName;
import android.annotation.NonNull;
import android.annotation.Nullable;
@ -337,7 +338,8 @@ public class Sensor {
if (mTestHalEnabled) {
return true;
}
return ServiceManager.checkService(IFace.DESCRIPTOR + "/" + halInstanceName) != null;
return ServiceManager.checkService(
remapFqName(IFace.DESCRIPTOR + "/" + halInstanceName)) != null;
}
/**