Face VHAL for user build
Bug: 326227403
Test: atest android.hardware.biometrics.face.* -c
Test: atest CtsBiometricsTestCases -c
Ignore-AOSP-First: Not release until 25q2
Change-Id: Ic300cca9f91af3dec3816f16e729656e91f36024
diff --git a/biometrics/common/config/include/config/Config.h b/biometrics/common/config/include/config/Config.h
index 0367832..b1affdc 100644
--- a/biometrics/common/config/include/config/Config.h
+++ b/biometrics/common/config/include/config/Config.h
@@ -100,7 +100,11 @@
} else if (std::holds_alternative<OptIntVec>(v)) {
for (auto x : std::get<OptIntVec>(v))
if (x.has_value()) os << x.value() << " ";
+ } else if (std::holds_alternative<OptString>(v)) {
+ OptString ov = std::get<OptString>(v);
+ if (ov.has_value()) os << ov.value();
}
+
return os.str();
}
std::string toString() const {
diff --git a/biometrics/face/aidl/Android.bp b/biometrics/face/aidl/Android.bp
index fadcde7..54d01a7 100644
--- a/biometrics/face/aidl/Android.bp
+++ b/biometrics/face/aidl/Android.bp
@@ -11,7 +11,7 @@
name: "android.hardware.biometrics.face",
vendor_available: true,
srcs: [
- "android/hardware/biometrics/face/**/*.aidl",
+ "android/hardware/biometrics/face/*.aidl",
],
imports: [
"android.hardware.biometrics.common-V4",
@@ -36,6 +36,10 @@
additional_shared_libraries: [
"libnativewindow",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.hardware.biometrics.face.virtual",
+ ],
},
},
versions_with_info: [
@@ -74,5 +78,39 @@
],
frozen: true,
+}
+aidl_interface {
+ name: "android.hardware.biometrics.face.virtualhal",
+ srcs: [
+ "android/hardware/biometrics/face/virtualhal/*.aidl",
+ ],
+ imports: [
+ "android.hardware.biometrics.common-V4",
+ "android.hardware.keymaster-V4",
+ "android.hardware.biometrics.face-V4",
+ ],
+ vendor_available: true,
+ unstable: true,
+ backend: {
+ java: {
+ platform_apis: true,
+ },
+ rust: {
+ enabled: false,
+ },
+ cpp: {
+ enabled: false,
+ },
+ ndk: {
+ additional_shared_libraries: [
+ "libnativewindow",
+ ],
+ apex_available: [
+ "com.android.hardware.biometrics.face.virtual",
+ "//apex_available:platform",
+ ],
+ },
+ },
+ frozen: false,
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index 26cb361..0dbf052 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -73,7 +73,7 @@
* Note that this interface allows multiple in-flight challenges. Invoking generateChallenge
* twice does not invalidate the first challenge. The challenge is invalidated only when:
* 1) Its lifespan exceeds the challenge timeout defined in the TEE.
- * 2) IFingerprint#revokeChallenge is invoked
+ * 2) IFace#revokeChallenge is invoked
*
* For example, the following is a possible table of valid challenges:
* ----------------------------------------------
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
new file mode 100644
index 0000000..a254120
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/AcquiredInfoAndVendorCode.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 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 android.hardware.biometrics.face.virtualhal;
+
+import android.hardware.biometrics.face.AcquiredInfo;
+
+/**
+ * @hide
+ */
+union AcquiredInfoAndVendorCode {
+ /**
+ * Acquired info as specified in AcqauiredInfo.aidl
+ */
+ AcquiredInfo acquiredInfo = AcquiredInfo.UNKNOWN;
+
+ /**
+ * Vendor specific code
+ */
+ int vendorCode;
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
new file mode 100644
index 0000000..7fbcf5d
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/EnrollmentProgressStep.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 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 android.hardware.biometrics.face.virtualhal;
+
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
+
+/**
+ * @hide
+ */
+parcelable EnrollmentProgressStep {
+ /**
+ * The duration of the enrollment step in milli-seconds
+ */
+ int durationMs;
+
+ /**
+ * The sequence of acquired info and vendor code to be issued by HAL during the step.
+ * The codes are evenly spread over the duration
+ */
+ AcquiredInfoAndVendorCode[] acquiredInfoAndVendorCodes;
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
new file mode 100644
index 0000000..1d3d934
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/IVirtualHal.aidl
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2024 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 android.hardware.biometrics.face.virtualhal;
+
+import android.hardware.biometrics.common.SensorStrength;
+import android.hardware.biometrics.face.FaceSensorType;
+import android.hardware.biometrics.face.IFace;
+import android.hardware.biometrics.face.virtualhal.AcquiredInfoAndVendorCode;
+import android.hardware.biometrics.face.virtualhal.NextEnrollment;
+
+/**
+ * @hide
+ */
+interface IVirtualHal {
+ /**
+ * The operation failed due to invalid input parameters, the error messages should
+ * gives more details
+ */
+ const int STATUS_INVALID_PARAMETER = 1;
+
+ /**
+ * Set Face Virtual HAL behavior parameters
+ */
+
+ /**
+ * setEnrollments
+ *
+ * Set the ids of the faces that were currently enrolled in the Virtual HAL,
+ *
+ * @param ids ids can contain 1 or more ids, each must be larger than 0
+ */
+ void setEnrollments(in int[] id);
+
+ /**
+ * setEnrollmentHit
+ *
+ * Set current face enrollment ids in Face Virtual HAL,
+ *
+ * @param ids ids can contain 1 or more ids, each must be larger than 0
+ */
+ void setEnrollmentHit(in int hit_id);
+
+ /**
+ * setNextEnrollment
+ *
+ * Set the next enrollment behavior
+ *
+ * @param next_enrollment specifies enrollment id, progress stages and final result
+ */
+ void setNextEnrollment(in NextEnrollment next_enrollment);
+
+ /**
+ * setAuthenticatorId
+ *
+ * Set authenticator id in virtual HAL, the id is returned in ISession#AuthenticatorId() call
+ *
+ * @param id authenticator id value, only applied to the sensor with SensorStrength::STRONG.
+ */
+ void setAuthenticatorId(in long id);
+
+ /**
+ * setChallenge
+ *
+ * Set the challenge generated by the virtual HAL, which is returned in
+ * ISessionCallback#onChallengeGenerated()
+ *
+ * @param challenge
+ */
+ void setChallenge(in long challenge);
+
+ /**
+ * setOperationAuthenticateFails
+ *
+ * Set whether to force authentication to fail. If true, the virtual hal will report failure on
+ * authentication attempt until it is set to false
+ *
+ * @param fail if true, then the next authentication will fail
+ */
+ void setOperationAuthenticateFails(in boolean fail);
+
+ /**
+ * setOperationAuthenticateLatency
+ *
+ * Set authentication latency in the virtual hal in a fixed value (single element) or random
+ * values (two elements representing the bound values)
+ * The latency simulates the delay from the time framework requesting HAL to authetication to
+ * the time when HAL is ready to perform authentication operations.
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of
+ * the following conditions
+ * 1. the array contains no element
+ * 2. the array contains more than two elements
+ * 3. the array contains any negative value
+ * The accompanying error message gives more detail
+ *
+ * @param latencyMs[] value(s) are in milli-seconds
+ */
+ void setOperationAuthenticateLatency(in int[] latencyMs);
+
+ /**
+ * setOperationAuthenticateDuration
+ *
+ * Set authentication duration covering the HAL authetication from start to end, including
+ * face capturing, and matching, acquired info reporting. In case a sequence of acquired
+ * info code are specified via setOperationAuthenticateAcquired(), the reporting is evenly
+ * distributed over the duration.
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
+ *
+ * @param duration value is in milli-seconds
+ */
+ void setOperationAuthenticateDuration(in int durationMs);
+
+ /**
+ * setOperationAuthenticateError
+ *
+ * Force authentication to error out for non-zero error
+ * Check
+ * hardware/interfaces/biometrics/face/aidl/default/aidl/android/hardware/biometrics/face/Error.aidl
+ * for valid error codes
+ *
+ * @param error if error < 1000
+ * non-vendor error
+ * else
+ * vendor error
+ */
+ void setOperationAuthenticateError(in int error);
+
+ /**
+ * setOperationAuthenticateAcquired
+ *
+ * Set one of more acquired info codes for the virtual hal to report during authentication
+ * Check
+ * hardware/interfaces/biometrics/face/aidl/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl
+ * for valid acquired info codes
+ *
+ * @param acquired[], one or more acquired info codes
+ */
+ void setOperationAuthenticateAcquired(in AcquiredInfoAndVendorCode[] acquired);
+
+ /**
+ * setOperationEnrollLatency
+ *
+ * Set enrollment latency in the virtual hal in a fixed value (single element) or random
+ * values (two elements representing the bound values)
+ * The latency simulates the delay from the time framework requesting HAL to enroll to the
+ * time when HAL is ready to perform enrollment operations.
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of
+ * the following conditions
+ * 1. the array contains no element
+ * 2. the array contains more than two elements
+ * 3. the array contains any negative value
+ * The accompanying error message gives more detail
+ *
+ * @param latencyMs[] value(s) are in milli-seconds
+ */
+ void setOperationEnrollLatency(in int[] latencyMs);
+
+ /**
+ * setOperationDetectInteractionLatency
+ *
+ * Set detect interaction latency in the virtual hal in a fixed value (single element) or random
+ * values (two elements representing the bound values)
+ * The latency simulates the delay from the time framework requesting HAL to detect interaction
+ * to the time when HAL is ready to perform detect interaction operations.
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in array falls in any of
+ * the following conditions
+ * 1. the array contains no element
+ * 2. the array contains more than two elements
+ * 3. the array contains any negative value
+ * The accompanying error message gives more detail
+ *
+ * @param latencyMs[] value(s) are in milli-seconds
+ */
+ void setOperationDetectInteractionLatency(in int[] latencyMs);
+
+ /**
+ * setOperationDetectInteractionFails
+ *
+ * Force detect interaction operation to fail
+ */
+ void setOperationDetectInteractionFails(in boolean error);
+
+ /**
+ * setLockout
+ *
+ * Whether to force to lockout on authentcation operation. If true, the virtual hal will report
+ * permanent lockout in processing authentication requrest, regardless of whether
+ * setLockoutEnable(true) is called or not.
+ *
+ * @param lockout, set to true if lockout is desired
+ */
+ void setLockout(in boolean lockout);
+
+ /**
+ * setLockoutEnable
+ *
+ * Whether to enable authentication-fail-based lockout tracking or not. The lock tracking
+ * includes both timed-based (aka temporary) lockout and permanent lockout.
+ *
+ * @param enable, set true to enable the lockout tracking
+ */
+ void setLockoutEnable(in boolean enable);
+
+ /**
+ * setLockoutTimedEnable
+ *
+ * Whether to enable authentication-fail-based time-based-lockout tracking or not.
+ *
+ * @param enable, set true to enable the time-basedlockout tracking
+ */
+ void setLockoutTimedEnable(in boolean enable);
+
+ /**
+ * setLockoutTimedThreshold
+ *
+ * Set the number of consecutive authentication failures that triggers the timed-based lock to
+ * occur
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
+ *
+ * @param threshold, the number of consecutive failures
+ */
+ void setLockoutTimedThreshold(in int threshold);
+
+ /**
+ * setLockoutTimedDuration
+ *
+ * Set the duration to expire timed-based lock during which there is no authentication failure
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
+ *
+ * @param duration, in milli-seconds
+ */
+ void setLockoutTimedDuration(in int durationMs);
+
+ /**
+ * setLockoutPermanentThreshold
+ *
+ * Set the number of consecutive authentication failures that triggers the permanent lock to
+ * occur
+ *
+ * This method fails with STATUS_INVALID_PARAMETERS if the passed-in value is negative
+ *
+ * @param threshold, the number of consecutive failures
+ */
+ void setLockoutPermanentThreshold(in int threshold);
+
+ /**
+ * resetConfigurations
+ *
+ * Reset all virtual hal configurations to default values
+ */
+ void resetConfigurations();
+
+ /**
+ * setType
+ *
+ * Configure virtual face sensor type
+ *
+ * @param type, sensor type as specified in FaceSensorType.aidl
+ *
+ */
+ void setType(in FaceSensorType type);
+
+ /**
+ * setSensorStrength
+ *
+ * Configure virtual face sensor strength
+ *
+ * @param sensor strength as specified in common/SensorStrength.aidl
+ */
+ void setSensorStrength(in SensorStrength strength);
+
+ /**
+ * getFaceHal
+ *
+ * @return IFace interface associated with IVirtualHal instance
+ */
+ IFace getFaceHal();
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
new file mode 100644
index 0000000..d3547a8
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/NextEnrollment.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2024 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 android.hardware.biometrics.face.virtualhal;
+
+/**
+ * @hide
+ */
+parcelable NextEnrollment {
+ /**
+ * Identifier of the next enrollment if successful
+ */
+ int id;
+
+ /**
+ * Specification of the progress steps of the next enrollment, each step consists of duration
+ * and sequence of acquired info codes to be generated by HAL.
+ * See EnrollmentProgressStep.aidl for more details
+ */
+ android.hardware.biometrics.face.virtualhal.EnrollmentProgressStep[] progressSteps;
+
+ /**
+ * Success or failure of the next enrollment
+ */
+ boolean result = true;
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
new file mode 100644
index 0000000..bf1a4b1
--- /dev/null
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/virtualhal/README.md
@@ -0,0 +1,3 @@
+The aidl files in this directory are used to control/configure face virtual hal
+via IVirtualHal interface
+
diff --git a/biometrics/face/aidl/default/Android.bp b/biometrics/face/aidl/default/Android.bp
index 685639c..bed0405 100644
--- a/biometrics/face/aidl/default/Android.bp
+++ b/biometrics/face/aidl/default/Android.bp
@@ -9,21 +9,13 @@
}
filegroup {
- name: "face-example.rc",
- srcs: ["face-example.rc"],
+ name: "face-virtual.rc",
+ srcs: ["face-virtual.rc"],
}
-filegroup {
- name: "face-example.xml",
- srcs: ["face-example.xml"],
-}
-
-cc_binary {
- name: "android.hardware.biometrics.face-service.example",
- relative_install_path: "hw",
- init_rc: [":face-example.rc"],
- vintf_fragments: [":face-example.xml"],
- vendor: true,
+cc_library_static {
+ name: "android.hardware.biometrics.face-service.lib",
+ vendor_available: true,
shared_libs: [
"libbinder_ndk",
@@ -32,32 +24,80 @@
],
srcs: [
"FakeLockoutTracker.cpp",
- "main.cpp",
"Face.cpp",
"FakeFaceEngine.cpp",
"Session.cpp",
+ "FaceConfig.cpp",
+ "VirtualHal.cpp",
+ "main.cpp",
],
include_dirs: [
"frameworks/native/aidl/gui",
],
stl: "c++_static",
- static_libs: [
+ whole_static_libs: [
"android.hardware.biometrics.common-V4-ndk",
+ "android.hardware.biometrics.common.config",
"android.hardware.biometrics.common.thread",
"android.hardware.biometrics.common.util",
+ "android.hardware.biometrics.face.virtualhal-ndk",
"android.hardware.biometrics.face-V4-ndk",
"android.hardware.common-V2-ndk",
"android.hardware.keymaster-V4-ndk",
"libandroid.hardware.biometrics.face.VirtualProps",
"libbase",
],
+ apex_available: [
+ "com.android.hardware.biometrics.face.virtual",
+ "//apex_available:platform",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.biometrics.face-service.example",
+ system_ext_specific: true,
+ relative_install_path: "hw",
+
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libnativewindow",
+ ],
+ whole_static_libs: [
+ "android.hardware.biometrics.face-service.lib",
+ ],
+ installable: false, // install APEX instead
+ apex_available: [
+ "com.android.hardware.biometrics.face.virtual",
+ "//apex_available:platform",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.biometrics.face-service.default",
+ vendor: true,
+ relative_install_path: "hw",
+ init_rc: ["face-default.rc"],
+ vintf_fragments: ["face-default.xml"],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libnativewindow",
+ ],
+ whole_static_libs: [
+ "android.hardware.biometrics.face-service.lib",
+ ],
}
sysprop_library {
name: "android.hardware.biometrics.face.VirtualProps",
srcs: ["face.sysprop"],
- property_owner: "Vendor",
- vendor: true,
+ property_owner: "Platform",
+ vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.hardware.biometrics.face.virtual",
+ ],
}
cc_test {
@@ -66,6 +106,7 @@
"tests/FakeFaceEngineTest.cpp",
"FakeFaceEngine.cpp",
"FakeLockoutTracker.cpp",
+ "FaceConfig.cpp",
],
shared_libs: [
"libbase",
@@ -81,6 +122,8 @@
"android.hardware.biometrics.common-V4-ndk",
"android.hardware.keymaster-V4-ndk",
"android.hardware.biometrics.common.util",
+ "android.hardware.biometrics.common.config",
+ "android.hardware.biometrics.common.thread",
],
vendor: true,
test_suites: ["general-tests"],
@@ -92,6 +135,7 @@
srcs: [
"tests/FakeLockoutTrackerTest.cpp",
"FakeLockoutTracker.cpp",
+ "FaceConfig.cpp",
],
shared_libs: [
"libbase",
@@ -107,8 +151,45 @@
"android.hardware.biometrics.common-V4-ndk",
"android.hardware.keymaster-V4-ndk",
"android.hardware.biometrics.common.util",
+ "android.hardware.biometrics.common.config",
+ "android.hardware.biometrics.common.thread",
],
vendor: true,
test_suites: ["general-tests"],
require_root: true,
}
+
+cc_test {
+ name: "android.hardware.biometrics.face.VirtualHalTest",
+ srcs: [
+ "tests/VirtualHalTest.cpp",
+ "FakeLockoutTracker.cpp",
+ "Face.cpp",
+ "FakeFaceEngine.cpp",
+ "Session.cpp",
+ "VirtualHal.cpp",
+ "FaceConfig.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libnativewindow",
+ "liblog",
+ ],
+ include_dirs: [
+ "frameworks/native/aidl/gui",
+ ],
+ static_libs: [
+ "android.hardware.biometrics.common-V4-ndk",
+ "android.hardware.biometrics.common.config",
+ "android.hardware.biometrics.common.thread",
+ "android.hardware.biometrics.common.util",
+ "android.hardware.biometrics.face-V4-ndk",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.keymaster-V4-ndk",
+ "libandroid.hardware.biometrics.face.VirtualProps",
+ "android.hardware.biometrics.face.virtualhal-ndk",
+ ],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index 5ae0df6..1543007 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -34,9 +34,7 @@
namespace aidl::android::hardware::biometrics::face {
const int kSensorId = 4;
-const common::SensorStrength kSensorStrength = FakeFaceEngine::GetSensorStrength();
const int kMaxEnrollmentsPerUser = 5;
-const FaceSensorType kSensorType = FakeFaceEngine::GetSensorType();
const bool kHalControlsPreview = true;
const std::string kHwComponentId = "faceSensor";
const std::string kHardwareVersion = "vendor/model/revision";
@@ -62,13 +60,13 @@
common::CommonProps commonProps;
commonProps.sensorId = kSensorId;
- commonProps.sensorStrength = kSensorStrength;
+ commonProps.sensorStrength = FakeFaceEngine::GetSensorStrength();
commonProps.maxEnrollmentsPerUser = kMaxEnrollmentsPerUser;
commonProps.componentInfo = {std::move(hw_component_info), std::move(sw_component_info)};
SensorProps props;
props.commonProps = std::move(commonProps);
- props.sensorType = kSensorType;
+ props.sensorType = FakeFaceEngine::GetSensorType();
props.halControlsPreview = kHalControlsPreview;
props.enrollPreviewWidth = 1080;
props.enrollPreviewHeight = 1920;
@@ -141,6 +139,30 @@
return STATUS_OK;
}
+const char* Face::type2String(FaceSensorType type) {
+ switch (type) {
+ case FaceSensorType::RGB:
+ return "rgb";
+ case FaceSensorType::IR:
+ return "ir";
+ default:
+ return "unknown";
+ }
+}
+
+const char* Face::strength2String(common::SensorStrength strength) {
+ switch (strength) {
+ case common::SensorStrength::STRONG:
+ return "STRONG";
+ case common::SensorStrength::WEAK:
+ return "WEAK";
+ case common::SensorStrength::CONVENIENCE:
+ return "CONVENIENCE";
+ default:
+ return "unknown";
+ }
+}
+
void Face::onHelp(int fd) {
dprintf(fd, "Virtual Face HAL commands:\n");
dprintf(fd, " help: print this help\n");
@@ -167,7 +189,6 @@
RESET_CONFIG_O(lockout);
RESET_CONFIG_O(operation_authenticate_fails);
RESET_CONFIG_O(operation_detect_interaction_fails);
- RESET_CONFIG_O(operation_enroll_fails);
RESET_CONFIG_V(operation_authenticate_latency);
RESET_CONFIG_V(operation_detect_interaction_latency);
RESET_CONFIG_V(operation_enroll_latency);
diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h
index 93fddb0..dbe6341 100644
--- a/biometrics/face/aidl/default/Face.h
+++ b/biometrics/face/aidl/default/Face.h
@@ -17,6 +17,7 @@
#pragma once
#include <aidl/android/hardware/biometrics/face/BnFace.h>
+#include "FaceConfig.h"
#include "Session.h"
namespace aidl::android::hardware::biometrics::face {
@@ -33,9 +34,20 @@
binder_status_t dump(int fd, const char** args, uint32_t numArgs);
binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
+ static FaceConfig& cfg() {
+ static FaceConfig* cfg = nullptr;
+ if (cfg == nullptr) {
+ cfg = new FaceConfig();
+ cfg->init();
+ }
+ return *cfg;
+ }
+ void resetConfigToDefault();
+ static const char* type2String(FaceSensorType type);
+ static const char* strength2String(common::SensorStrength strength);
+
private:
std::shared_ptr<Session> mSession;
- void resetConfigToDefault();
void onHelp(int);
};
diff --git a/biometrics/face/aidl/default/FaceConfig.cpp b/biometrics/face/aidl/default/FaceConfig.cpp
new file mode 100644
index 0000000..a91d7cc
--- /dev/null
+++ b/biometrics/face/aidl/default/FaceConfig.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#define LOG_TAG "FaceConfig"
+
+#include "FaceConfig.h"
+
+#include <android-base/logging.h>
+
+#include <face.sysprop.h>
+
+using namespace ::android::face::virt;
+
+namespace aidl::android::hardware::biometrics::face {
+
+// Wrapper to system property access functions
+#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_) \
+ ConfigValue _NAME_##Getter() { \
+ return FaceHalProperties::_NAME_(); \
+ } \
+ bool _NAME_##Setter(const ConfigValue& v) { \
+ return FaceHalProperties::_NAME_(std::get<_T_>(v)); \
+ }
+
+CREATE_GETTER_SETTER_WRAPPER(type, OptString)
+CREATE_GETTER_SETTER_WRAPPER(enrollments, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(enrollment_hit, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(next_enrollment, OptString)
+CREATE_GETTER_SETTER_WRAPPER(authenticator_id, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(challenge, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(strength, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_acquired, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_enroll_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(lockout, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_permanent_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(features, OptIntVec)
+
+// Name, Getter, Setter, Parser and default value
+#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
+static Config::Data configData[] = {
+ {NGS(type), &Config::parseString, "rgb"},
+ {NGS(enrollments), &Config::parseIntVec, ""},
+ {NGS(enrollment_hit), &Config::parseInt32, "0"},
+ {NGS(next_enrollment), &Config::parseString,
+ "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"},
+ {NGS(authenticator_id), &Config::parseInt64, "0"},
+ {NGS(challenge), &Config::parseInt64, ""},
+ {NGS(strength), &Config::parseString, "strong"},
+ {NGS(operation_authenticate_fails), &Config::parseBool, "false"},
+ {NGS(operation_authenticate_latency), &Config::parseIntVec, ""},
+ {NGS(operation_authenticate_duration), &Config::parseInt32, "500"},
+ {NGS(operation_authenticate_error), &Config::parseInt32, "0"},
+ {NGS(operation_authenticate_acquired), &Config::parseString, ""},
+ {NGS(operation_enroll_latency), &Config::parseIntVec, ""},
+ {NGS(operation_detect_interaction_latency), &Config::parseIntVec, ""},
+ {NGS(operation_detect_interaction_fails), &Config::parseBool, "false"},
+ {NGS(lockout), &Config::parseBool, "false"},
+ {NGS(lockout_enable), &Config::parseBool, "false"},
+ {NGS(lockout_timed_enable), &Config::parseBool, "false"},
+ {NGS(lockout_timed_threshold), &Config::parseInt32, "3"},
+ {NGS(lockout_timed_duration), &Config::parseInt32, "10000"},
+ {NGS(lockout_permanent_threshold), &Config::parseInt32, "5"},
+ {NGS(features), &Config::parseIntVec, ""}};
+
+Config::Data* FaceConfig::getConfigData(int* size) {
+ *size = sizeof(configData) / sizeof(configData[0]);
+ return configData;
+}
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FaceConfig.h b/biometrics/face/aidl/default/FaceConfig.h
new file mode 100644
index 0000000..64b62e0
--- /dev/null
+++ b/biometrics/face/aidl/default/FaceConfig.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include "config/Config.h"
+
+namespace aidl::android::hardware::biometrics::face {
+
+class FaceConfig : public Config {
+ Config::Data* getConfigData(int* size) override;
+};
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index bf75874..70d9f2d 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -23,6 +23,7 @@
#include <face.sysprop.h>
+#include "Face.h"
#include "util/CancellationSignal.h"
#include "util/Util.h"
@@ -31,23 +32,23 @@
namespace aidl::android::hardware::biometrics::face {
FaceSensorType FakeFaceEngine::GetSensorType() {
- std::string type = FaceHalProperties::type().value_or("");
+ std::string type = Face::cfg().get<std::string>("type");
if (type == "IR") {
return FaceSensorType::IR;
} else {
- FaceHalProperties::type("RGB");
+ Face::cfg().set<std::string>("type", "RGB");
return FaceSensorType::RGB;
}
}
common::SensorStrength FakeFaceEngine::GetSensorStrength() {
- std::string strength = FaceHalProperties::strength().value_or("");
+ std::string strength = Face::cfg().get<std::string>("strength");
if (strength == "convenience") {
return common::SensorStrength::CONVENIENCE;
} else if (strength == "weak") {
return common::SensorStrength::WEAK;
} else {
- FaceHalProperties::strength("strong");
+ // Face::cfg().set<std::string>("strength", "strong");
return common::SensorStrength::STRONG;
}
}
@@ -56,13 +57,13 @@
BEGIN_OP(0);
std::uniform_int_distribution<int64_t> dist;
auto challenge = dist(mRandom);
- FaceHalProperties::challenge(challenge);
+ Face::cfg().set<int64_t>("challenge", challenge);
cb->onChallengeGenerated(challenge);
}
void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
BEGIN_OP(0);
- FaceHalProperties::challenge({});
+ Face::cfg().set<int64_t>("challenge", 0);
cb->onChallengeRevoked(challenge);
}
void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
@@ -71,7 +72,7 @@
EnrollmentType /*enrollmentType*/,
const std::vector<Feature>& /*features*/,
const std::future<void>& cancel) {
- BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency()));
+ BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_enroll_latency")));
// Do proper HAT verification in the real implementation.
if (hat.mac.empty()) {
@@ -80,18 +81,19 @@
return;
}
- // Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
- // ------:-----------------------------------------:--------------
- // | | |--->enrollment success (true/false)
- // | |--> progress_steps
+ // Format:
+ // <id>:<progress_ms-[acquiredInfo,...],...:<success>
+ // -------:--------------------------------------------------:--------------
+ // | | |--->enrollment
+ // success (true/false) | |--> progress_steps
// |
// |-->enrollment id
//
//
- // progress_steps
+ // progress_steps:
// <progress_duration>-[acquiredInfo,...]+
// ---------------------------- ---------------------
- // | |-> sequence of acquiredInfo code
+ // | |-> sequence of acquiredInfo code
// | --> time duration of the step in ms
//
// E.g. 1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true
@@ -101,7 +103,7 @@
//
std::string defaultNextEnrollment =
"1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true";
- auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment);
+ auto nextEnroll = Face::cfg().get<std::string>("next_enrollment");
auto parts = Util::split(nextEnroll, ":");
if (parts.size() != 3) {
LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
@@ -137,19 +139,19 @@
if (left == 0 && !IS_TRUE(parts[2])) { // end and failed
LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
- FaceHalProperties::next_enrollment({});
+ Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
} else { // progress and update props if last time
LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
if (left == 0) {
- auto enrollments = FaceHalProperties::enrollments();
+ auto enrollments = Face::cfg().getopt<OptIntVec>("enrollments");
enrollments.emplace_back(enrollmentId);
- FaceHalProperties::enrollments(enrollments);
- FaceHalProperties::next_enrollment({});
+ Face::cfg().setopt<OptIntVec>("enrollments", enrollments);
+ Face::cfg().setopt<OptString>("next_enrollment", std::nullopt);
// change authenticatorId after new enrollment
- auto id = FaceHalProperties::authenticator_id().value_or(0);
+ auto id = Face::cfg().get<std::int64_t>("authenticator_id");
auto newId = id + 1;
- FaceHalProperties::authenticator_id(newId);
+ Face::cfg().set<std::int64_t>("authenticator_id", newId);
LOG(INFO) << "Enrolled: " << enrollmentId;
}
cb->onEnrollmentProgress(enrollmentId, left);
@@ -159,10 +161,12 @@
void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
const std::future<void>& cancel) {
- BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency()));
+ BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_authenticate_latency")));
- auto id = FaceHalProperties::enrollment_hit().value_or(0);
- auto enrolls = FaceHalProperties::enrollments();
+ // SLEEP_MS(3000); //emulate hw HAL
+
+ auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+ auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
auto vec2str = [](std::vector<AcquiredInfo> va) {
@@ -192,10 +196,12 @@
}
int64_t now = Util::getSystemNanoTime();
- int64_t duration =
- FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
- auto acquired =
- FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
+ int64_t duration = Face::cfg().get<std::int32_t>("operation_authenticate_duration");
+ auto acquired = Face::cfg().get<std::string>("operation_authenticate_acquired");
+ if (acquired.empty()) {
+ Face::cfg().set<std::string>("operation_authenticate_acquired", defaultAcquiredInfo);
+ acquired = defaultAcquiredInfo;
+ }
auto acquiredInfos = Util::parseIntSequence(acquired);
int N = acquiredInfos.size();
@@ -211,21 +217,21 @@
int i = 0;
do {
- if (FaceHalProperties::lockout().value_or(false)) {
+ if (Face::cfg().get<bool>("lockout")) {
LOG(ERROR) << "Fail: lockout";
cb->onLockoutPermanent();
cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
return;
}
- if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
+ if (Face::cfg().get<bool>("operation_authenticate_fails")) {
LOG(ERROR) << "Fail: operation_authenticate_fails";
mLockoutTracker.addFailedAttempt(cb);
cb->onAuthenticationFailed();
return;
}
- auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
+ auto err = Face::cfg().get<std::int32_t>("operation_authenticate_error");
if (err != 0) {
LOG(ERROR) << "Fail: operation_authenticate_error";
auto ec = convertError(err);
@@ -249,6 +255,15 @@
LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
<< ")";
i++;
+
+ // the captured face id may change during authentication period
+ auto idnew = Face::cfg().get<std::int32_t>("enrollment_hit");
+ if (id != idnew) {
+ isEnrolled = std::find(enrolls.begin(), enrolls.end(), idnew) != enrolls.end();
+ LOG(INFO) << "enrollment_hit changed from " << id << " to " << idnew;
+ id = idnew;
+ break;
+ }
}
SLEEP_MS(duration / N);
@@ -292,9 +307,9 @@
}
void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
- BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+ BEGIN_OP(getLatency(Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
- if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
+ if (Face::cfg().get<bool>("operation_detect_interaction_fails")) {
LOG(ERROR) << "Fail: operation_detect_interaction_fails";
cb->onError(Error::VENDOR, 0 /* vendorError */);
return;
@@ -306,8 +321,8 @@
return;
}
- auto id = FaceHalProperties::enrollment_hit().value_or(0);
- auto enrolls = FaceHalProperties::enrollments();
+ auto id = Face::cfg().get<std::int32_t>("enrollment_hit");
+ auto enrolls = Face::cfg().getopt<OptIntVec>("enrollments");
auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
if (id <= 0 || !isEnrolled) {
LOG(ERROR) << "Fail: not enrolled";
@@ -321,7 +336,7 @@
void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
BEGIN_OP(0);
std::vector<int32_t> enrollments;
- for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
+ for (const auto& enrollmentId : Face::cfg().getopt<OptIntVec>("enrollments")) {
if (enrollmentId) {
enrollments.push_back(*enrollmentId);
}
@@ -334,20 +349,20 @@
BEGIN_OP(0);
std::vector<std::optional<int32_t>> newEnrollments;
- for (const auto& enrollment : FaceHalProperties::enrollments()) {
+ for (const auto& enrollment : Face::cfg().getopt<OptIntVec>("enrollments")) {
auto id = enrollment.value_or(0);
if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
newEnrollments.emplace_back(id);
}
}
- FaceHalProperties::enrollments(newEnrollments);
+ Face::cfg().setopt<OptIntVec>("enrollments", newEnrollments);
cb->onEnrollmentsRemoved(enrollmentIds);
}
void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
BEGIN_OP(0);
- if (FaceHalProperties::enrollments().empty()) {
+ if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
return;
}
@@ -365,7 +380,7 @@
Feature feature, bool enabled) {
BEGIN_OP(0);
- if (FaceHalProperties::enrollments().empty()) {
+ if (Face::cfg().getopt<OptIntVec>("enrollments").empty()) {
LOG(ERROR) << "Unable to set feature, enrollments are empty";
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
return;
@@ -377,7 +392,7 @@
return;
}
- auto features = FaceHalProperties::features();
+ auto features = Face::cfg().getopt<OptIntVec>("features");
auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
return *theFeature == (int)feature;
@@ -389,7 +404,7 @@
features.push_back((int)feature);
}
- FaceHalProperties::features(features);
+ Face::cfg().setopt<OptIntVec>("features", features);
cb->onFeatureSet(feature);
}
@@ -399,22 +414,22 @@
if (GetSensorStrength() != common::SensorStrength::STRONG) {
cb->onAuthenticatorIdRetrieved(0);
} else {
- cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
+ cb->onAuthenticatorIdRetrieved(Face::cfg().get<std::int64_t>("authenticator_id"));
}
}
void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
BEGIN_OP(0);
- int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
+ int64_t authenticatorId = Face::cfg().get<std::int64_t>("authenticator_id");
int64_t newId = authenticatorId + 1;
- FaceHalProperties::authenticator_id(newId);
+ Face::cfg().set<std::int64_t>("authenticator_id", newId);
cb->onAuthenticatorIdInvalidated(newId);
}
void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
const keymaster::HardwareAuthToken& /*hat*/) {
BEGIN_OP(0);
- FaceHalProperties::lockout(false);
+ Face::cfg().set<bool>("lockout", false);
mLockoutTracker.reset();
cb->onLockoutCleared();
}
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.cpp b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
index 70bf08e..35d7c28 100644
--- a/biometrics/face/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.cpp
@@ -19,6 +19,7 @@
#include "FakeLockoutTracker.h"
#include <android-base/logging.h>
#include <face.sysprop.h>
+#include "Face.h"
#include "util/Util.h"
using namespace ::android::face::virt;
@@ -36,15 +37,15 @@
}
void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
- bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
- bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
+ bool lockoutEnabled = Face::cfg().get<bool>("lockout_enable");
+ bool timedLockoutenabled = Face::cfg().get<bool>("lockout_timed_enable");
if (lockoutEnabled) {
mFailedCount++;
mTimedFailedCount++;
mLastFailedTime = Util::getSystemNanoTime();
- int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
+ int32_t lockoutTimedThreshold = Face::cfg().get<std::int32_t>("lockout_timed_threshold");
int32_t lockoutPermanetThreshold =
- FaceHalProperties::lockout_permanent_threshold().value_or(5);
+ Face::cfg().get<std::int32_t>("lockout_permanent_threshold");
if (mFailedCount >= lockoutPermanetThreshold) {
mCurrentMode = LockoutMode::kPermanent;
LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
@@ -68,7 +69,7 @@
}
int32_t FakeLockoutTracker::getTimedLockoutDuration() {
- return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
+ return Face::cfg().get<std::int32_t>("lockout_timed_duration");
}
int64_t FakeLockoutTracker::getLockoutTimeLeft() {
diff --git a/biometrics/face/aidl/default/VirtualHal.cpp b/biometrics/face/aidl/default/VirtualHal.cpp
new file mode 100644
index 0000000..52ac23b
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.cpp
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <unordered_map>
+
+#include "VirtualHal.h"
+
+#include <android-base/logging.h>
+
+#include "util/CancellationSignal.h"
+
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHalAidl"
+
+namespace aidl::android::hardware::biometrics::face {
+using AcquiredInfoAndVendorCode = virtualhal::AcquiredInfoAndVendorCode;
+using Tag = AcquiredInfoAndVendorCode::Tag;
+
+::ndk::ScopedAStatus VirtualHal::setEnrollments(const std::vector<int32_t>& enrollments) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().setopt<OptIntVec>("enrollments", intVec2OptIntVec(enrollments));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setEnrollmentHit(int32_t enrollment_hit) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<std::int32_t>("enrollment_hit", enrollment_hit);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setNextEnrollment(
+ const ::aidl::android::hardware::biometrics::face::NextEnrollment& next_enrollment) {
+ Face::cfg().sourcedFromAidl();
+ std::ostringstream os;
+ os << next_enrollment.id << ":";
+
+ int stepSize = next_enrollment.progressSteps.size();
+ for (int i = 0; i < stepSize; i++) {
+ auto& step = next_enrollment.progressSteps[i];
+ os << step.durationMs;
+ int acSize = step.acquiredInfoAndVendorCodes.size();
+ for (int j = 0; j < acSize; j++) {
+ if (j == 0) os << "-[";
+ auto& acquiredInfoAndVendorCode = step.acquiredInfoAndVendorCodes[j];
+ if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+ os << acquiredInfoAndVendorCode.get<Tag::vendorCode>();
+ else if (acquiredInfoAndVendorCode.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+ os << (int)acquiredInfoAndVendorCode.get<Tag::acquiredInfo>();
+ else
+ LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode union tag";
+ if (j == acSize - 1)
+ os << "]";
+ else
+ os << ",";
+ }
+ if (i == stepSize - 1)
+ os << ":";
+ else
+ os << ",";
+ }
+
+ os << (next_enrollment.result ? "true" : "false");
+ Face::cfg().set<std::string>("next_enrollment", os.str());
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setAuthenticatorId(int64_t in_id) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int64_t>("authenticator_id", in_id);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setChallenge(int64_t in_challenge) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int64_t>("challenge", in_challenge);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateFails(bool in_fail) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<bool>("operation_authenticate_fails", in_fail);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateLatency(
+ const std::vector<int32_t>& in_latency) {
+ ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().setopt<OptIntVec>("operation_authenticate_latency", intVec2OptIntVec(in_latency));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateDuration(int32_t in_duration) {
+ if (in_duration < 0) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int32_t>("operation_authenticate_duration", in_duration);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateError(int32_t in_error) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int32_t>("operation_authenticate_error", in_error);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationAuthenticateAcquired(
+ const std::vector<AcquiredInfoAndVendorCode>& in_acquired) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().setopt<OptIntVec>("operation_authenticate_acquired",
+ acquiredInfoVec2OptIntVec(in_acquired));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationEnrollLatency(const std::vector<int32_t>& in_latency) {
+ ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+ if (!status.isOk()) {
+ return status;
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().setopt<OptIntVec>("operation_enroll_latency", intVec2OptIntVec(in_latency));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionLatency(
+ const std::vector<int32_t>& in_latency) {
+ ndk::ScopedAStatus status = sanityCheckLatency(in_latency);
+ if (!status.isOk()) {
+ return status;
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().setopt<OptIntVec>("operation_detect_interact_latency",
+ intVec2OptIntVec(in_latency));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setOperationDetectInteractionFails(bool in_fails) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<bool>("operation_detect_interaction_fails", in_fails);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockout(bool in_lockout) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<bool>("lockout", in_lockout);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutEnable(bool in_enable) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<bool>("lockout_enable", in_enable);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedEnable(bool in_enable) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<bool>("lockout_timed_enable", in_enable);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedThreshold(int32_t in_threshold) {
+ if (in_threshold < 0) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int32_t>("lockout_timed_threshold", in_threshold);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutTimedDuration(int32_t in_duration) {
+ if (in_duration < 0) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER, "Error: duration can not be negative"));
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int32_t>("lockout_timed_duration", in_duration);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setLockoutPermanentThreshold(int32_t in_threshold) {
+ if (in_threshold < 0) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER, "Error: threshold can not be negative"));
+ }
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<int32_t>("lockout_permanent_threshold", in_threshold);
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::resetConfigurations() {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().init();
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setType(
+ ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<std::string>("type", Face::type2String(in_type));
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::setSensorStrength(common::SensorStrength in_strength) {
+ Face::cfg().sourcedFromAidl();
+ Face::cfg().set<std::string>("strength", Face::strength2String(in_strength));
+ return ndk::ScopedAStatus::ok();
+}
+
+OptIntVec VirtualHal::intVec2OptIntVec(const std::vector<int32_t>& in_vec) {
+ OptIntVec optIntVec;
+ std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+ [](int value) { return std::optional<int>(value); });
+ return optIntVec;
+}
+
+OptIntVec VirtualHal::acquiredInfoVec2OptIntVec(
+ const std::vector<AcquiredInfoAndVendorCode>& in_vec) {
+ OptIntVec optIntVec;
+ std::transform(in_vec.begin(), in_vec.end(), std::back_inserter(optIntVec),
+ [](AcquiredInfoAndVendorCode ac) {
+ int value;
+ if (ac.getTag() == AcquiredInfoAndVendorCode::acquiredInfo)
+ value = (int)ac.get<Tag::acquiredInfo>();
+ else if (ac.getTag() == AcquiredInfoAndVendorCode::vendorCode)
+ value = ac.get<Tag::vendorCode>();
+ else
+ LOG(FATAL) << "ERROR: wrong AcquiredInfoAndVendorCode tag";
+ return std::optional<int>(value);
+ });
+ return optIntVec;
+}
+
+::ndk::ScopedAStatus VirtualHal::sanityCheckLatency(const std::vector<int32_t>& in_latency) {
+ if (in_latency.size() == 0 || in_latency.size() > 2) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER,
+ "Error: input input array must contain 1 or 2 elements"));
+ }
+
+ for (auto x : in_latency) {
+ if (x < 0) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IVirtualHal::STATUS_INVALID_PARAMETER,
+ "Error: input data must not be negative"));
+ }
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus VirtualHal::getFaceHal(std::shared_ptr<IFace>* pFace) {
+ *pFace = mFp;
+ return ndk::ScopedAStatus::ok();
+}
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/VirtualHal.h b/biometrics/face/aidl/default/VirtualHal.h
new file mode 100644
index 0000000..f2ac552
--- /dev/null
+++ b/biometrics/face/aidl/default/VirtualHal.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/biometrics/face/virtualhal/BnVirtualHal.h>
+
+#include "Face.h"
+
+namespace aidl::android::hardware::biometrics::face {
+using namespace virtualhal;
+class VirtualHal : public BnVirtualHal {
+ public:
+ VirtualHal(std::shared_ptr<Face> fp) : mFp(fp) {}
+
+ ::ndk::ScopedAStatus setEnrollments(const std::vector<int32_t>& in_id) override;
+ ::ndk::ScopedAStatus setEnrollmentHit(int32_t in_hit_id) override;
+ ::ndk::ScopedAStatus setNextEnrollment(
+ const ::aidl::android::hardware::biometrics::face::NextEnrollment& in_next_enrollment)
+ override;
+ ::ndk::ScopedAStatus setAuthenticatorId(int64_t in_id) override;
+ ::ndk::ScopedAStatus setChallenge(int64_t in_challenge) override;
+ ::ndk::ScopedAStatus setOperationAuthenticateFails(bool in_fail) override;
+ ::ndk::ScopedAStatus setOperationAuthenticateLatency(
+ const std::vector<int32_t>& in_latency) override;
+ ::ndk::ScopedAStatus setOperationAuthenticateDuration(int32_t in_duration) override;
+ ::ndk::ScopedAStatus setOperationAuthenticateError(int32_t in_error) override;
+ ::ndk::ScopedAStatus setOperationAuthenticateAcquired(
+ const std::vector<AcquiredInfoAndVendorCode>& in_acquired) override;
+ ::ndk::ScopedAStatus setOperationEnrollLatency(const std::vector<int32_t>& in_latency) override;
+ ::ndk::ScopedAStatus setOperationDetectInteractionLatency(
+ const std::vector<int32_t>& in_latency) override;
+ ::ndk::ScopedAStatus setOperationDetectInteractionFails(bool in_fails) override;
+ ::ndk::ScopedAStatus setLockout(bool in_lockout) override;
+ ::ndk::ScopedAStatus setLockoutEnable(bool in_enable) override;
+ ::ndk::ScopedAStatus setLockoutTimedEnable(bool in_enable) override;
+ ::ndk::ScopedAStatus setLockoutTimedThreshold(int32_t in_threshold) override;
+ ::ndk::ScopedAStatus setLockoutTimedDuration(int32_t in_duration) override;
+ ::ndk::ScopedAStatus setLockoutPermanentThreshold(int32_t in_threshold) override;
+ ::ndk::ScopedAStatus resetConfigurations() override;
+ ::ndk::ScopedAStatus setType(
+ ::aidl::android::hardware::biometrics::face::FaceSensorType in_type) override;
+ ::ndk::ScopedAStatus setSensorStrength(common::SensorStrength in_strength) override;
+ ::ndk::ScopedAStatus getFaceHal(std::shared_ptr<IFace>* _aidl_return);
+
+ private:
+ OptIntVec intVec2OptIntVec(const std::vector<int32_t>& intVec);
+ OptIntVec acquiredInfoVec2OptIntVec(const std::vector<AcquiredInfoAndVendorCode>& intVec);
+ ::ndk::ScopedAStatus sanityCheckLatency(const std::vector<int32_t>& in_latency);
+ std::shared_ptr<Face> mFp;
+};
+
+} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/apex/Android.bp b/biometrics/face/aidl/default/apex/Android.bp
index 86c4e12..c4632d4 100644
--- a/biometrics/face/aidl/default/apex/Android.bp
+++ b/biometrics/face/aidl/default/apex/Android.bp
@@ -23,7 +23,7 @@
key: "com.android.hardware.key",
certificate: ":com.android.hardware.certificate",
updatable: false,
- vendor: true,
+ system_ext_specific: true,
binaries: [
// hal
@@ -31,9 +31,7 @@
],
prebuilts: [
// init_rc
- "face-example-apex.rc",
- // vintf_fragment
- "face-example-apex.xml",
+ "face-virtual-apex.rc",
],
overrides: [
@@ -42,21 +40,7 @@
}
prebuilt_etc {
- name: "face-example-apex.rc",
- src: ":gen-face-example-apex.rc",
- installable: false,
-}
-
-genrule {
- name: "gen-face-example-apex.rc",
- srcs: [":face-example.rc"],
- out: ["face-example-apex.rc"],
- cmd: "sed -e 's@/vendor/bin/@/apex/com.android.hardware.biometrics.face.virtual/bin/@' $(in) > $(out)",
-}
-
-prebuilt_etc {
- name: "face-example-apex.xml",
- src: ":face-example.xml",
- sub_dir: "vintf",
+ name: "face-virtual-apex.rc",
+ src: ":face-virtual.rc",
installable: false,
}
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
index e69de29..6ad579c 100644
--- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -0,0 +1,133 @@
+props {
+ owner: Vendor
+ module: "android.face.virt.FaceHalProperties"
+ prop {
+ api_name: "authenticator_id"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.authenticator_id"
+ }
+ prop {
+ api_name: "challenge"
+ type: Long
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.challenge"
+ }
+ prop {
+ api_name: "enrollment_hit"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.enrollment_hit"
+ }
+ prop {
+ api_name: "enrollments"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.enrollments"
+ }
+ prop {
+ api_name: "features"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.features"
+ }
+ prop {
+ api_name: "lockout"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.lockout"
+ }
+ prop {
+ api_name: "lockout_enable"
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.lockout_enable"
+ }
+ prop {
+ api_name: "lockout_permanent_threshold"
+ type: Integer
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
+ }
+ prop {
+ api_name: "lockout_timed_duration"
+ type: Integer
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
+ }
+ prop {
+ api_name: "lockout_timed_enable"
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
+ }
+ prop {
+ api_name: "lockout_timed_threshold"
+ type: Integer
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
+ }
+ prop {
+ api_name: "next_enrollment"
+ type: String
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.next_enrollment"
+ }
+ prop {
+ api_name: "operation_authenticate_acquired"
+ type: String
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_acquired"
+ }
+ prop {
+ api_name: "operation_authenticate_duration"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_duration"
+ }
+ prop {
+ api_name: "operation_authenticate_error"
+ type: Integer
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_error"
+ }
+ prop {
+ api_name: "operation_authenticate_fails"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_fails"
+ }
+ prop {
+ api_name: "operation_authenticate_latency"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_authenticate_latency"
+ }
+ prop {
+ api_name: "operation_detect_interaction_fails"
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
+ }
+ prop {
+ api_name: "operation_detect_interaction_latency"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
+ }
+ prop {
+ api_name: "operation_enroll_latency"
+ type: IntegerList
+ access: ReadWrite
+ prop_name: "vendor.face.virtual.operation_enroll_latency"
+ }
+ prop {
+ api_name: "strength"
+ type: String
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.strength"
+ enum_values: "convenience|weak|strong"
+ }
+ prop {
+ api_name: "type"
+ type: String
+ access: ReadWrite
+ prop_name: "persist.vendor.face.virtual.type"
+ enum_values: "IR|RGB"
+ }
+}
diff --git a/biometrics/face/aidl/default/face-default.rc b/biometrics/face/aidl/default/face-default.rc
new file mode 100644
index 0000000..7ce4249
--- /dev/null
+++ b/biometrics/face/aidl/default/face-default.rc
@@ -0,0 +1,8 @@
+service vendor.face-default /vendor/bin/hw/android.hardware.biometrics.face-service.default default
+ class hal
+ user nobody
+ group nobody
+ interface aidl android.hardware.biometrics.face.IFace/default
+ oneshot
+ disabled
+
diff --git a/biometrics/face/aidl/default/face-example.xml b/biometrics/face/aidl/default/face-default.xml
similarity index 81%
rename from biometrics/face/aidl/default/face-example.xml
rename to biometrics/face/aidl/default/face-default.xml
index 2b39b3d..94569de 100644
--- a/biometrics/face/aidl/default/face-example.xml
+++ b/biometrics/face/aidl/default/face-default.xml
@@ -2,6 +2,6 @@
<hal format="aidl">
<name>android.hardware.biometrics.face</name>
<version>4</version>
- <fqname>IFace/virtual</fqname>
+ <fqname>IFace/default</fqname>
</hal>
</manifest>
diff --git a/biometrics/face/aidl/default/face-example.rc b/biometrics/face/aidl/default/face-example.rc
deleted file mode 100644
index b0d82c6..0000000
--- a/biometrics/face/aidl/default/face-example.rc
+++ /dev/null
@@ -1,8 +0,0 @@
-service vendor.face-example /vendor/bin/hw/android.hardware.biometrics.face-service.example
- class hal
- user nobody
- group nobody
- interface aidl android.hardware.biometrics.face.IFace/virtual
- oneshot
- disabled
-
diff --git a/biometrics/face/aidl/default/face-virtual.rc b/biometrics/face/aidl/default/face-virtual.rc
new file mode 100644
index 0000000..8fb0a7b
--- /dev/null
+++ b/biometrics/face/aidl/default/face-virtual.rc
@@ -0,0 +1,8 @@
+service face-virtual /apex/com.android.hardware.biometrics.face.virtual/bin/hw/android.hardware.biometrics.face-service.example virtual
+ class hal
+ user nobody
+ group nobody
+ interface aidl android.hardware.biometrics.face.virtualhal.IVirtualHal/virtual
+ oneshot
+ disabled
+
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 997fd67..ec2b92b 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -7,7 +7,7 @@
prop {
prop_name: "persist.vendor.face.virtual.type"
type: String
- scope: Internal
+ scope: Public
access: ReadWrite
enum_values: "IR|RGB"
api_name: "type"
@@ -17,7 +17,7 @@
prop {
prop_name: "persist.vendor.face.virtual.strength"
type: String
- scope: Internal
+ scope: Public
access: ReadWrite
enum_values: "convenience|weak|strong"
api_name: "strength"
@@ -27,7 +27,7 @@
prop {
prop_name: "persist.vendor.face.virtual.enrollments"
type: IntegerList
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "enrollments"
}
@@ -36,7 +36,7 @@
prop {
prop_name: "persist.vendor.face.virtual.features"
type: IntegerList
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "features"
}
@@ -46,7 +46,7 @@
prop {
prop_name: "vendor.face.virtual.enrollment_hit"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "enrollment_hit"
}
@@ -60,7 +60,7 @@
prop {
prop_name: "vendor.face.virtual.next_enrollment"
type: String
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "next_enrollment"
}
@@ -69,7 +69,7 @@
prop {
prop_name: "vendor.face.virtual.authenticator_id"
type: Long
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "authenticator_id"
}
@@ -78,7 +78,7 @@
prop {
prop_name: "vendor.face.virtual.challenge"
type: Long
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "challenge"
}
@@ -87,7 +87,7 @@
prop {
prop_name: "vendor.face.virtual.lockout"
type: Boolean
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout"
}
@@ -96,7 +96,7 @@
prop {
prop_name: "vendor.face.virtual.operation_authenticate_fails"
type: Boolean
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_authenticate_fails"
}
@@ -105,27 +105,18 @@
prop {
prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
type: Boolean
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_detect_interaction_fails"
}
-# force all enroll operations to fail
-prop {
- prop_name: "vendor.face.virtual.operation_enroll_fails"
- type: Boolean
- scope: Internal
- access: ReadWrite
- api_name: "operation_enroll_fails"
-}
-
# add a latency to authentication operations
# Note that this latency is the initial authentication latency that occurs before
# the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
prop {
prop_name: "vendor.face.virtual.operation_authenticate_latency"
type: IntegerList
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_authenticate_latency"
}
@@ -134,7 +125,7 @@
prop {
prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
type: IntegerList
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_detect_interaction_latency"
}
@@ -143,7 +134,7 @@
prop {
prop_name: "vendor.face.virtual.operation_enroll_latency"
type: IntegerList
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_enroll_latency"
}
@@ -153,7 +144,7 @@
prop {
prop_name: "vendor.face.virtual.operation_authenticate_duration"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_authenticate_duration"
}
@@ -162,7 +153,7 @@
prop {
prop_name: "vendor.face.virtual.operation_authenticate_error"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_authenticate_error"
}
@@ -171,7 +162,7 @@
prop {
prop_name: "vendor.face.virtual.operation_authenticate_acquired"
type: String
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "operation_authenticate_acquired"
}
@@ -180,7 +171,7 @@
prop {
prop_name: "persist.vendor.face.virtual.lockout_enable"
type: Boolean
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout_enable"
}
@@ -189,7 +180,7 @@
prop {
prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
type: Boolean
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout_timed_enable"
}
@@ -198,7 +189,7 @@
prop {
prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout_timed_threshold"
}
@@ -207,7 +198,7 @@
prop {
prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout_timed_duration"
}
@@ -216,7 +207,7 @@
prop {
prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
type: Integer
- scope: Internal
+ scope: Public
access: ReadWrite
api_name: "lockout_permanent_threshold"
}
diff --git a/biometrics/face/aidl/default/main.cpp b/biometrics/face/aidl/default/main.cpp
index 38e1c63..75a4479 100644
--- a/biometrics/face/aidl/default/main.cpp
+++ b/biometrics/face/aidl/default/main.cpp
@@ -14,25 +14,49 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "FaceVirtualHal"
+
#include "Face.h"
+#include "VirtualHal.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using aidl::android::hardware::biometrics::face::Face;
+using aidl::android::hardware::biometrics::face::VirtualHal;
-int main() {
- LOG(INFO) << "Face HAL started";
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ LOG(ERROR) << "Missing argument -> exiting, Valid arguments:[default|virtual]";
+ return EXIT_FAILURE;
+ }
+ LOG(INFO) << "Face HAL started: " << argv[1];
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Face> hal = ndk::SharedRefBase::make<Face>();
+ std::shared_ptr<VirtualHal> hal_vhal = ndk::SharedRefBase::make<VirtualHal>(hal);
- const std::string instance = std::string(Face::descriptor) + "/virtual";
- binder_status_t status =
- AServiceManager_registerLazyService(hal->asBinder().get(), instance.c_str());
- CHECK_EQ(status, STATUS_OK);
+ if (strcmp(argv[1], "default") == 0) {
+ const std::string instance = std::string(Face::descriptor) + "/default";
+ auto binder = hal->asBinder();
+ binder_status_t status =
+ AServiceManager_registerLazyService(binder.get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+ LOG(INFO) << "started IFace/default";
+ } else if (strcmp(argv[1], "virtual") == 0) {
+ const std::string instance = std::string(VirtualHal::descriptor) + "/virtual";
+ auto binder = hal_vhal->asBinder();
+ binder_status_t status =
+ AServiceManager_registerLazyService(binder.get(), instance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+ LOG(INFO) << "started IVirtualHal/virtual";
+ } else {
+ LOG(ERROR) << "Unexpected argument: " << argv[1];
+ return EXIT_FAILURE;
+ }
AServiceManager_forceLazyServicesPersist(true);
ABinderProcess_joinThreadPool();
- return EXIT_FAILURE; // should not reach
+ return EXIT_FAILURE; // should not reach here
}
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index 8c39b58..d448532 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -21,6 +21,7 @@
#include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
#include <android-base/logging.h>
+#include "Face.h"
#include "FakeFaceEngine.h"
#include "util/Util.h"
@@ -141,12 +142,12 @@
}
void TearDown() override {
- FaceHalProperties::enrollments({});
- FaceHalProperties::challenge({});
- FaceHalProperties::features({});
- FaceHalProperties::authenticator_id({});
- FaceHalProperties::strength("");
- FaceHalProperties::operation_detect_interaction_latency({});
+ Face::cfg().setopt<OptIntVec>("enrollments", {});
+ Face::cfg().set<std::int64_t>("challenge", 0);
+ Face::cfg().setopt<OptIntVec>("features", {});
+ Face::cfg().set<std::int64_t>("authenticator_id", 0);
+ Face::cfg().set<std::string>("strength", "");
+ Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
}
FakeFaceEngine mEngine;
@@ -160,81 +161,83 @@
TEST_F(FakeFaceEngineTest, GenerateChallenge) {
mEngine.generateChallengeImpl(mCallback.get());
- ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
+ ASSERT_EQ(Face::cfg().get<std::int64_t>("challenge"), mCallback->mLastChallenge);
}
TEST_F(FakeFaceEngineTest, RevokeChallenge) {
- auto challenge = FaceHalProperties::challenge().value_or(10);
+ auto challenge = Face::cfg().get<std::int64_t>("challenge");
mEngine.revokeChallengeImpl(mCallback.get(), challenge);
- ASSERT_FALSE(FaceHalProperties::challenge().has_value());
+ ASSERT_FALSE(Face::cfg().get<std::int64_t>("challenge"));
ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
}
TEST_F(FakeFaceEngineTest, ResetLockout) {
- FaceHalProperties::lockout(true);
+ Face::cfg().set<bool>("lockout", true);
mEngine.resetLockoutImpl(mCallback.get(), {});
ASSERT_FALSE(mCallback->mLockoutPermanent);
- ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
+ ASSERT_FALSE(Face::cfg().get<bool>("lockout"));
}
TEST_F(FakeFaceEngineTest, AuthenticatorId) {
- FaceHalProperties::authenticator_id(50);
+ Face::cfg().set<std::int64_t>("authenticator_id", 50);
mEngine.getAuthenticatorIdImpl(mCallback.get());
ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
}
TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
- FaceHalProperties::strength("weak");
- FaceHalProperties::authenticator_id(500);
+ Face::cfg().set<std::string>("strength", "weak");
+ Face::cfg().set<std::int64_t>("authenticator_id", 500);
mEngine.getAuthenticatorIdImpl(mCallback.get());
ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
}
TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
- FaceHalProperties::authenticator_id(500);
+ Face::cfg().set<std::int64_t>("authenticator_id", 500);
mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
- ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
+ ASSERT_NE(500, Face::cfg().get<std::int64_t>("authenticator_id"));
ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
}
TEST_F(FakeFaceEngineTest, Enroll) {
- FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
+ Face::cfg().set<std::string>("next_enrollment",
+ "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:true");
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
mCancel.get_future());
- ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
- ASSERT_EQ(1, FaceHalProperties::enrollments().size());
- ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
+ ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+ ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments").size());
+ ASSERT_EQ(1, Face::cfg().getopt<OptIntVec>("enrollments")[0].value());
ASSERT_EQ(1, mCallback->mLastEnrolled);
ASSERT_EQ(0, mCallback->mRemaining);
}
TEST_F(FakeFaceEngineTest, EnrollFails) {
- FaceHalProperties::next_enrollment("1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
+ Face::cfg().set<std::string>("next_enrollment",
+ "1,0:1000-[21,5,6,7,1],1100-[1118,1108,1]:false");
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
mCancel.get_future());
- ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
- ASSERT_EQ(0, FaceHalProperties::enrollments().size());
+ ASSERT_FALSE(Face::cfg().getopt<OptString>("next_enrollment").has_value());
+ ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
}
TEST_F(FakeFaceEngineTest, EnrollCancel) {
- FaceHalProperties::next_enrollment("1:2000-[21,8,9],300:false");
+ Face::cfg().set<std::string>("next_enrollment", "1:2000-[21,8,9],300:false");
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mCancel.set_value();
mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
mCancel.get_future());
ASSERT_EQ(Error::CANCELED, mCallback->mError);
ASSERT_EQ(-1, mCallback->mLastEnrolled);
- ASSERT_EQ(0, FaceHalProperties::enrollments().size());
- ASSERT_TRUE(FaceHalProperties::next_enrollment().has_value());
+ ASSERT_EQ(0, Face::cfg().getopt<OptIntVec>("enrollments").size());
+ ASSERT_FALSE(Face::cfg().get<std::string>("next_enrollment").empty());
}
TEST_F(FakeFaceEngineTest, Authenticate) {
- FaceHalProperties::enrollments({100});
- FaceHalProperties::enrollment_hit(100);
+ Face::cfg().setopt<OptIntVec>("enrollments", {100});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 100);
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
ASSERT_EQ(100, mCallback->mLastAuthenticated);
@@ -242,32 +245,32 @@
}
TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
- FaceHalProperties::enrollments({100});
- FaceHalProperties::enrollment_hit(100);
+ Face::cfg().setopt<OptIntVec>("enrollments", {100});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 100);
mCancel.set_value();
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
ASSERT_EQ(Error::CANCELED, mCallback->mError);
}
TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
- FaceHalProperties::enrollments({3});
- FaceHalProperties::enrollment_hit(100);
+ Face::cfg().setopt<OptIntVec>("enrollments", {3});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 100);
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
ASSERT_EQ(Error::TIMEOUT, mCallback->mError);
ASSERT_TRUE(mCallback->mAuthenticateFailed);
}
TEST_F(FakeFaceEngineTest, DetectInteraction) {
- FaceHalProperties::enrollments({100});
- FaceHalProperties::enrollment_hit(100);
+ Face::cfg().setopt<OptIntVec>("enrollments", {100});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 100);
ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
}
TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
- FaceHalProperties::enrollments({100});
- FaceHalProperties::enrollment_hit(100);
+ Face::cfg().setopt<OptIntVec>("enrollments", {100});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 100);
mCancel.set_value();
mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
ASSERT_EQ(Error::CANCELED, mCallback->mError);
@@ -279,7 +282,7 @@
}
TEST_F(FakeFaceEngineTest, SetFeature) {
- FaceHalProperties::enrollments({1});
+ Face::cfg().setopt<OptIntVec>("enrollments", {1});
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
auto features = mCallback->mFeatures;
@@ -294,7 +297,7 @@
}
TEST_F(FakeFaceEngineTest, ToggleFeature) {
- FaceHalProperties::enrollments({1});
+ Face::cfg().setopt<OptIntVec>("enrollments", {1});
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
mEngine.getFeaturesImpl(mCallback.get());
@@ -310,7 +313,7 @@
}
TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
- FaceHalProperties::enrollments({1});
+ Face::cfg().setopt<OptIntVec>("enrollments", {1});
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
mEngine.getFeaturesImpl(mCallback.get());
@@ -319,7 +322,7 @@
}
TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
- FaceHalProperties::enrollments({1});
+ Face::cfg().setopt<OptIntVec>("enrollments", {1});
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -335,7 +338,7 @@
}
TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
- FaceHalProperties::enrollments({1});
+ Face::cfg().setopt<OptIntVec>("enrollments", {1});
keymaster::HardwareAuthToken hat{.mac = {2, 4}};
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
@@ -352,7 +355,7 @@
}
TEST_F(FakeFaceEngineTest, Enumerate) {
- FaceHalProperties::enrollments({120, 3});
+ Face::cfg().setopt<OptIntVec>("enrollments", {120, 3});
mEngine.enumerateEnrollmentsImpl(mCallback.get());
auto enrolls = mCallback->mLastEnrollmentsEnumerated;
ASSERT_FALSE(enrolls.empty());
@@ -361,7 +364,7 @@
}
TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
- FaceHalProperties::enrollments({120, 3, 100});
+ Face::cfg().setopt<OptIntVec>("enrollments", {120, 3, 100});
mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
mEngine.enumerateEnrollmentsImpl(mCallback.get());
auto enrolls = mCallback->mLastEnrollmentsEnumerated;
@@ -372,9 +375,9 @@
}
TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
- FaceHalProperties::lockout(true);
- FaceHalProperties::enrollments({33});
- FaceHalProperties::enrollment_hit(33);
+ Face::cfg().set<bool>("lockout", true);
+ Face::cfg().setopt<OptIntVec>("enrollments", {33});
+ Face::cfg().set<std::int32_t>("enrollment_hit", 33);
auto cancelFuture = mCancel.get_future();
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
@@ -382,28 +385,30 @@
mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
ASSERT_FALSE(mCallback->mLockoutPermanent);
- FaceHalProperties::enrollment_hit(33);
+ Face::cfg().set<std::int32_t>("enrollment_hit", 33);
mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
ASSERT_EQ(33, mCallback->mLastAuthenticated);
ASSERT_FALSE(mCallback->mAuthenticateFailed);
}
TEST_F(FakeFaceEngineTest, LatencyDefault) {
- FaceHalProperties::operation_detect_interaction_latency({});
- ASSERT_EQ(DEFAULT_LATENCY,
- mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+ Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
+ ASSERT_EQ(DEFAULT_LATENCY, mEngine.getLatency(Face::cfg().getopt<OptIntVec>(
+ "operation_detect_interaction_latency")));
}
TEST_F(FakeFaceEngineTest, LatencyFixed) {
- FaceHalProperties::operation_detect_interaction_latency({10});
- ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+ Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {10});
+ ASSERT_EQ(10, mEngine.getLatency(
+ Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
}
TEST_F(FakeFaceEngineTest, LatencyRandom) {
- FaceHalProperties::operation_detect_interaction_latency({1, 1000});
+ Face::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {1, 1000});
std::set<int32_t> latencySet;
for (int i = 0; i < 100; i++) {
- auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency());
+ auto x = mEngine.getLatency(
+ Face::cfg().getopt<OptIntVec>("operation_detect_interaction_latency"));
ASSERT_TRUE(x >= 1 && x <= 1000);
latencySet.insert(x);
}
diff --git a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
index fa07d1d..8564f6b 100644
--- a/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
+#include "Face.h"
#include "FakeLockoutTracker.h"
#include "util/Util.h"
@@ -103,19 +104,21 @@
static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
void SetUp() override {
- FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
- FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
- FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+ Face::cfg().set<std::int32_t>("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD);
+ Face::cfg().set<std::int32_t>("lockout_timed_duration", LOCKOUT_TIMED_DURATION);
+ Face::cfg().set<std::int32_t>("lockout_permanent_threshold", LOCKOUT_PERMANENT_THRESHOLD);
+ Face::cfg().set<bool>("lockout_enable", false);
+ Face::cfg().set<bool>("lockout", false);
mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
}
void TearDown() override {
// reset to default
- FaceHalProperties::lockout_timed_threshold(5);
- FaceHalProperties::lockout_timed_duration(20);
- FaceHalProperties::lockout_permanent_threshold(10000);
- FaceHalProperties::lockout_enable(false);
- FaceHalProperties::lockout(false);
+ Face::cfg().set<std::int32_t>("lockout_timed_threshold", 5);
+ Face::cfg().set<std::int32_t>("lockout_timed_duration", 20);
+ Face::cfg().set<std::int32_t>("lockout_permanent_threshold", 10000);
+ Face::cfg().set<bool>("lockout_enable", false);
+ Face::cfg().set<bool>("lockout", false);
}
FakeLockoutTracker mLockoutTracker;
@@ -123,7 +126,7 @@
};
TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
- FaceHalProperties::lockout_enable(false);
+ Face::cfg().set<bool>("lockout_enable", false);
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
mLockoutTracker.addFailedAttempt(mCallback.get());
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
@@ -131,7 +134,7 @@
}
TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
- FaceHalProperties::lockout_enable(true);
+ Face::cfg().set<bool>("lockout_enable", true);
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -145,8 +148,8 @@
}
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
- FaceHalProperties::lockout_enable(true);
- FaceHalProperties::lockout_timed_enable(true);
+ Face::cfg().set<bool>("lockout_enable", true);
+ Face::cfg().set<bool>("lockout_timed_enable", true);
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -168,8 +171,8 @@
}
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
- FaceHalProperties::lockout_enable(true);
- FaceHalProperties::lockout_timed_enable(true);
+ Face::cfg().set<bool>("lockout_enable", true);
+ Face::cfg().set<bool>("lockout_timed_enable", true);
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
mLockoutTracker.addFailedAttempt(mCallback.get());
@@ -182,8 +185,8 @@
}
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
- FaceHalProperties::lockout_enable(true);
- FaceHalProperties::lockout_timed_enable(true);
+ Face::cfg().set<bool>("lockout_enable", true);
+ Face::cfg().set<bool>("lockout_timed_enable", true);
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
ASSERT_EQ(0, mCallback->mLockoutTimed);
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
@@ -198,7 +201,7 @@
}
TEST_F(FakeLockoutTrackerTest, resetLockout) {
- FaceHalProperties::lockout_enable(true);
+ Face::cfg().set<bool>("lockout_enable", true);
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
mLockoutTracker.addFailedAttempt(mCallback.get());
diff --git a/biometrics/face/aidl/default/tests/VirtualHalTest.cpp b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
new file mode 100644
index 0000000..2f19805
--- /dev/null
+++ b/biometrics/face/aidl/default/tests/VirtualHalTest.cpp
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <android/binder_process.h>
+#include <face.sysprop.h>
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+
+#include "Face.h"
+#include "VirtualHal.h"
+
+using namespace ::android::face::virt;
+using namespace ::aidl::android::hardware::biometrics::face;
+
+namespace aidl::android::hardware::biometrics::face {
+
+class VirtualHalTest : public ::testing::Test {
+ public:
+ static const int32_t STATUS_FAILED_TO_SET_PARAMETER = 2;
+
+ protected:
+ void SetUp() override {
+ mHal = ndk::SharedRefBase::make<Face>();
+ mVhal = ndk::SharedRefBase::make<VirtualHal>(mHal);
+ ASSERT_TRUE(mVhal != nullptr);
+ mHal->resetConfigToDefault();
+ }
+
+ void TearDown() override { mHal->resetConfigToDefault(); }
+
+ std::shared_ptr<VirtualHal> mVhal;
+
+ ndk::ScopedAStatus validateNonNegativeInputOfInt32(const char* name,
+ ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+ const std::vector<int32_t>& in_good);
+
+ private:
+ std::shared_ptr<Face> mHal;
+};
+
+ndk::ScopedAStatus VirtualHalTest::validateNonNegativeInputOfInt32(
+ const char* name, ndk::ScopedAStatus (VirtualHal::*f)(int32_t),
+ const std::vector<int32_t>& in_params_good) {
+ ndk::ScopedAStatus status;
+ for (auto& param : in_params_good) {
+ status = (*mVhal.*f)(param);
+ if (!status.isOk()) return status;
+ if (Face::cfg().get<int32_t>(name) != param) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+ "Error: fail to set non-negative parameter"));
+ }
+ }
+
+ int32_t old_param = Face::cfg().get<int32_t>(name);
+ status = (*mVhal.*f)(-1);
+ if (status.isOk()) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER, "Error: should return NOK"));
+ }
+ if (status.getServiceSpecificError() != IVirtualHal::STATUS_INVALID_PARAMETER) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+ "Error: unexpected return error code"));
+ }
+ if (Face::cfg().get<int32_t>(name) != old_param) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ VirtualHalTest::STATUS_FAILED_TO_SET_PARAMETER,
+ "Error: unexpected parameter change on failed attempt"));
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+TEST_F(VirtualHalTest, init) {
+ mVhal->setLockout(false);
+ ASSERT_TRUE(Face::cfg().get<bool>("lockout") == false);
+ ASSERT_TRUE(Face::cfg().get<std::string>("type") == "rgb");
+ ASSERT_TRUE(Face::cfg().get<std::string>("strength") == "strong");
+ std::int64_t id = Face::cfg().get<std::int64_t>("authenticator_id");
+ ASSERT_TRUE(Face::cfg().get<std::int64_t>("authenticator_id") == 0);
+ ASSERT_TRUE(Face::cfg().getopt<OptIntVec>("enrollments") == OptIntVec());
+}
+
+TEST_F(VirtualHalTest, enrollment_hit_int32) {
+ mVhal->setEnrollmentHit(11);
+ ASSERT_TRUE(Face::cfg().get<int32_t>("enrollment_hit") == 11);
+}
+
+TEST_F(VirtualHalTest, next_enrollment) {
+ struct {
+ std::string nextEnrollmentStr;
+ face::NextEnrollment nextEnrollment;
+ } testData[] = {
+ {"1:20:true", {1, {{20}}, true}},
+ {"1:50,60,70:true", {1, {{50}, {60}, {70}}, true}},
+ {"2:50-[21],60,70-[4,1002,1]:false",
+ {2,
+ {{50, {{AcquiredInfo::START}}},
+ {60},
+ {70, {{AcquiredInfo::TOO_DARK}, {1002}, {AcquiredInfo::GOOD}}}},
+ false}},
+ };
+
+ for (auto& d : testData) {
+ mVhal->setNextEnrollment(d.nextEnrollment);
+ ASSERT_TRUE(Face::cfg().get<std::string>("next_enrollment") == d.nextEnrollmentStr);
+ }
+}
+
+TEST_F(VirtualHalTest, authenticator_id_int64) {
+ mVhal->setAuthenticatorId(12345678900);
+ ASSERT_TRUE(Face::cfg().get<int64_t>("authenticator_id") == 12345678900);
+}
+
+TEST_F(VirtualHalTest, opeationAuthenticateFails_bool) {
+ mVhal->setOperationAuthenticateFails(true);
+ ASSERT_TRUE(Face::cfg().get<bool>("operation_authenticate_fails"));
+}
+
+TEST_F(VirtualHalTest, operationAuthenticateAcquired_int32_vector) {
+ using Tag = AcquiredInfoAndVendorCode::Tag;
+ std::vector<AcquiredInfoAndVendorCode> ac{
+ {AcquiredInfo::START}, {AcquiredInfo::TOO_FAR}, {1023}};
+ mVhal->setOperationAuthenticateAcquired(ac);
+ OptIntVec ac_get = Face::cfg().getopt<OptIntVec>("operation_authenticate_acquired");
+ ASSERT_TRUE(ac_get.size() == ac.size());
+ for (int i = 0; i < ac.size(); i++) {
+ int acCode = (ac[i].getTag() == Tag::acquiredInfo) ? (int)ac[i].get<Tag::acquiredInfo>()
+ : ac[i].get<Tag::vendorCode>();
+ ASSERT_TRUE(acCode == ac_get[i]);
+ }
+}
+
+TEST_F(VirtualHalTest, type) {
+ struct {
+ FaceSensorType type;
+ const char* typeStr;
+ } typeMap[] = {{FaceSensorType::RGB, "rgb"},
+ {FaceSensorType::IR, "ir"},
+ {FaceSensorType::UNKNOWN, "unknown"}};
+ for (auto const& x : typeMap) {
+ mVhal->setType(x.type);
+ ASSERT_TRUE(Face::cfg().get<std::string>("type") == x.typeStr);
+ }
+}
+
+TEST_F(VirtualHalTest, sensorStrength) {
+ struct {
+ common::SensorStrength strength;
+ const char* strengthStr;
+ } strengths[] = {{common::SensorStrength::CONVENIENCE, "CONVENIENCE"},
+ {common::SensorStrength::WEAK, "WEAK"},
+ {common::SensorStrength::STRONG, "STRONG"}};
+
+ for (auto const& x : strengths) {
+ mVhal->setSensorStrength(x.strength);
+ ASSERT_TRUE(Face::cfg().get<std::string>("strength") == x.strengthStr);
+ }
+}
+
+TEST_F(VirtualHalTest, setLatency) {
+ ndk::ScopedAStatus status;
+ std::vector<int32_t> in_lats[] = {{1}, {2, 3}, {5, 4}};
+ for (auto const& in_lat : in_lats) {
+ status = mVhal->setOperationAuthenticateLatency(in_lat);
+ ASSERT_TRUE(status.isOk());
+ OptIntVec out_lat = Face::cfg().getopt<OptIntVec>("operation_authenticate_latency");
+ ASSERT_TRUE(in_lat.size() == out_lat.size());
+ for (int i = 0; i < in_lat.size(); i++) {
+ ASSERT_TRUE(in_lat[i] == out_lat[i]);
+ }
+ }
+
+ std::vector<int32_t> bad_in_lats[] = {{}, {1, 2, 3}, {1, -3}};
+ for (auto const& in_lat : bad_in_lats) {
+ status = mVhal->setOperationAuthenticateLatency(in_lat);
+ ASSERT_TRUE(!status.isOk());
+ ASSERT_TRUE(status.getServiceSpecificError() == IVirtualHal::STATUS_INVALID_PARAMETER);
+ }
+}
+
+TEST_F(VirtualHalTest, setOperationAuthenticateDuration) {
+ ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+ "operation_authenticate_duration", &IVirtualHal::setOperationAuthenticateDuration,
+ {0, 33});
+ ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedDuration) {
+ ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+ "lockout_timed_duration", &IVirtualHal::setLockoutTimedDuration, {0, 35});
+ ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutTimedThreshold) {
+ ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+ "lockout_timed_threshold", &IVirtualHal::setLockoutTimedThreshold, {0, 36});
+ ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setLockoutPermanentThreshold) {
+ ndk::ScopedAStatus status = validateNonNegativeInputOfInt32(
+ "lockout_permanent_threshold", &IVirtualHal::setLockoutPermanentThreshold, {0, 37});
+ ASSERT_TRUE(status.isOk());
+}
+
+TEST_F(VirtualHalTest, setOthers) {
+ // Verify that there is no CHECK() failures
+ mVhal->setEnrollments({7, 6, 5});
+ mVhal->setChallenge(111222333444555666);
+ mVhal->setOperationAuthenticateError(4);
+ mVhal->setOperationEnrollLatency({4, 5});
+ mVhal->setLockout(false);
+ mVhal->setLockoutEnable(false);
+}
+
+} // namespace aidl::android::hardware::biometrics::face
+
+int main(int argc, char** argv) {
+ testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/keymaster/aidl/Android.bp b/keymaster/aidl/Android.bp
index d416d2d..c101f56 100644
--- a/keymaster/aidl/Android.bp
+++ b/keymaster/aidl/Android.bp
@@ -20,6 +20,7 @@
},
ndk: {
apex_available: [
+ "com.android.hardware.biometrics.face.virtual",
"com.android.hardware.biometrics.fingerprint.virtual",
"//apex_available:platform",
],