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
This commit is contained in:
Jeff Pu
2024-06-10 15:03:50 +00:00
parent d46c0f4396
commit a3c5736d5d
29 changed files with 1641 additions and 214 deletions

View File

@@ -100,7 +100,11 @@ class Config {
} 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 {

View File

@@ -11,7 +11,7 @@ aidl_interface {
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 @@ aidl_interface {
additional_shared_libraries: [
"libnativewindow",
],
apex_available: [
"//apex_available:platform",
"com.android.hardware.biometrics.face.virtual",
],
},
},
versions_with_info: [
@@ -74,5 +78,39 @@ aidl_interface {
],
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,
}

View File

@@ -73,7 +73,7 @@ interface ISession {
* 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:
* ----------------------------------------------

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -0,0 +1,3 @@
The aidl files in this directory are used to control/configure face virtual hal
via IVirtualHal interface

View File

@@ -9,21 +9,13 @@ package {
}
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 @@ cc_binary {
],
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 @@ cc_test {
"tests/FakeFaceEngineTest.cpp",
"FakeFaceEngine.cpp",
"FakeLockoutTracker.cpp",
"FaceConfig.cpp",
],
shared_libs: [
"libbase",
@@ -81,6 +122,8 @@ cc_test {
"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 @@ cc_test {
srcs: [
"tests/FakeLockoutTrackerTest.cpp",
"FakeLockoutTracker.cpp",
"FaceConfig.cpp",
],
shared_libs: [
"libbase",
@@ -107,8 +151,45 @@ cc_test {
"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,
}

View File

@@ -34,9 +34,7 @@ using namespace ::android::face::virt;
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 @@ ndk::ScopedAStatus Face::getSensorProps(std::vector<SensorProps>* return_val) {
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 @@ binder_status_t Face::handleShellCommand(int in, int out, int err, const char**
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 @@ void Face::resetConfigToDefault() {
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);

View File

@@ -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 @@ class Face : public BnFace {
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);
};

View File

@@ -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

View File

@@ -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

View File

@@ -23,6 +23,7 @@
#include <face.sysprop.h>
#include "Face.h"
#include "util/CancellationSignal.h"
#include "util/Util.h"
@@ -31,23 +32,23 @@ using namespace ::android::face::virt;
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 @@ void FakeFaceEngine::generateChallengeImpl(ISessionCallback* cb) {
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 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA
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 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA
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 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA
//
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 @@ void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA
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::enrollImpl(ISessionCallback* cb, const keymaster::HardwareA
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 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
}
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 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
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 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
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 @@ std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
}
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 @@ void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::futu
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::detectInteractionImpl(ISessionCallback* cb, const std::futu
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 @@ void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
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 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw
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 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw
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 @@ void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::Hardw
features.push_back((int)feature);
}
FaceHalProperties::features(features);
Face::cfg().setopt<OptIntVec>("features", features);
cb->onFeatureSet(feature);
}
@@ -399,22 +414,22 @@ void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
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();
}

View File

@@ -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::reset(bool dueToTimerExpire) {
}
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 @@ FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
}
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() {

View File

@@ -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

View File

@@ -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

View File

@@ -23,7 +23,7 @@ apex {
key: "com.android.hardware.key",
certificate: ":com.android.hardware.certificate",
updatable: false,
vendor: true,
system_ext_specific: true,
binaries: [
// hal
@@ -31,9 +31,7 @@ apex {
],
prebuilts: [
// init_rc
"face-example-apex.rc",
// vintf_fragment
"face-example-apex.xml",
"face-virtual-apex.rc",
],
overrides: [
@@ -42,21 +40,7 @@ apex {
}
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,
}

View File

@@ -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"
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -7,7 +7,7 @@ owner: Vendor
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 {
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 {
prop_name: "persist.vendor.face.virtual.enrollments"
type: IntegerList
scope: Internal
scope: Public
access: ReadWrite
api_name: "enrollments"
}
@@ -36,7 +36,7 @@ prop {
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 {
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 {
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 {
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 {
prop_name: "vendor.face.virtual.challenge"
type: Long
scope: Internal
scope: Public
access: ReadWrite
api_name: "challenge"
}
@@ -87,7 +87,7 @@ prop {
prop {
prop_name: "vendor.face.virtual.lockout"
type: Boolean
scope: Internal
scope: Public
access: ReadWrite
api_name: "lockout"
}
@@ -96,7 +96,7 @@ prop {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
type: Integer
scope: Internal
scope: Public
access: ReadWrite
api_name: "lockout_permanent_threshold"
}

View File

@@ -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
}

View File

@@ -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 @@ class FakeFaceEngineTest : public ::testing::Test {
}
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, one_eq_one) {
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, Authenticate) {
}
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, GetFeatureEmpty) {
}
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, SetFeature) {
}
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, ToggleFeature) {
}
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, TurningOffNonExistentFeatureDoesNothing) {
}
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, SetMultipleFeatures) {
}
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, SetMultipleFeaturesAndTurnOffSome) {
}
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, Enumerate) {
}
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, RemoveEnrollments) {
}
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 @@ TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
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);
}

View File

@@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include "Face.h"
#include "FakeLockoutTracker.h"
#include "util/Util.h"
@@ -103,19 +104,21 @@ class FakeLockoutTrackerTest : public ::testing::Test {
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 @@ class FakeLockoutTrackerTest : public ::testing::Test {
};
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, addFailedAttemptDisable) {
}
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, addFailedAttemptPermanent) {
}
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, addFailedAttemptLockoutTimed) {
}
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, addFailedAttemptLockout_TimedThenPermanent) {
}
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, addFailedAttemptLockoutTimedTwice) {
}
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());

View File

@@ -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();
}

View File

@@ -20,6 +20,7 @@ aidl_interface {
},
ndk: {
apex_available: [
"com.android.hardware.biometrics.face.virtual",
"com.android.hardware.biometrics.fingerprint.virtual",
"//apex_available:platform",
],