Face Virtual HAL lockout support
Bug: 294254230 Test: atest android.hardware.biometrics.face.FakeFaceEngineTest Test: atest android.hardware.biometrics.face.FakeLockoutTrackerTest Change-Id: I4ed3ada4734f595d5f9ac70cf5ed2a94bed378c6
This commit is contained in:
parent
d27ec7f9b5
commit
3e7448dc2b
8 changed files with 580 additions and 17 deletions
|
@ -30,6 +30,7 @@ cc_binary {
|
|||
"libnativewindow",
|
||||
],
|
||||
srcs: [
|
||||
"FakeLockoutTracker.cpp",
|
||||
"main.cpp",
|
||||
"Face.cpp",
|
||||
"FakeFaceEngine.cpp",
|
||||
|
@ -63,6 +64,33 @@ cc_test {
|
|||
srcs: [
|
||||
"tests/FakeFaceEngineTest.cpp",
|
||||
"FakeFaceEngine.cpp",
|
||||
"FakeLockoutTracker.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder_ndk",
|
||||
"libnativewindow",
|
||||
],
|
||||
include_dirs: [
|
||||
"frameworks/native/aidl/gui",
|
||||
],
|
||||
static_libs: [
|
||||
"libandroid.hardware.biometrics.face.VirtualProps",
|
||||
"android.hardware.biometrics.face-V4-ndk",
|
||||
"android.hardware.biometrics.common-V4-ndk",
|
||||
"android.hardware.keymaster-V4-ndk",
|
||||
"android.hardware.biometrics.common.util",
|
||||
],
|
||||
vendor: true,
|
||||
test_suites: ["general-tests"],
|
||||
require_root: true,
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "android.hardware.biometrics.face.FakeLockoutTrackerTest",
|
||||
srcs: [
|
||||
"tests/FakeLockoutTrackerTest.cpp",
|
||||
"FakeLockoutTracker.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
|
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* Copyright (C) 2023 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 "FaceVirtualHalEngine"
|
||||
|
||||
#include "FakeFaceEngine.h"
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
@ -186,6 +204,10 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
|
|||
return;
|
||||
}
|
||||
|
||||
if (mLockoutTracker.checkIfLockout(cb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
if (FaceHalProperties::lockout().value_or(false)) {
|
||||
|
@ -197,6 +219,7 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
|
|||
|
||||
if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
|
||||
LOG(ERROR) << "Fail: operation_authenticate_fails";
|
||||
mLockoutTracker.addFailedAttempt(cb);
|
||||
cb->onAuthenticationFailed();
|
||||
return;
|
||||
}
|
||||
|
@ -231,10 +254,12 @@ void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationI
|
|||
} while (!Util::hasElapsed(now, duration));
|
||||
|
||||
if (id > 0 && isEnrolled) {
|
||||
mLockoutTracker.reset();
|
||||
cb->onAuthenticationSucceeded(id, {} /* hat */);
|
||||
return;
|
||||
} else {
|
||||
LOG(ERROR) << "Fail: face not enrolled";
|
||||
mLockoutTracker.addFailedAttempt(cb);
|
||||
cb->onAuthenticationFailed();
|
||||
cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
|
||||
return;
|
||||
|
@ -389,6 +414,7 @@ void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
|
|||
const keymaster::HardwareAuthToken& /*hat*/) {
|
||||
BEGIN_OP(0);
|
||||
FaceHalProperties::lockout(false);
|
||||
mLockoutTracker.reset();
|
||||
cb->onLockoutCleared();
|
||||
}
|
||||
|
||||
|
|
|
@ -16,18 +16,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#define LOG_TAG "FaceVirtualHal"
|
||||
|
||||
#include <aidl/android/hardware/biometrics/common/SensorStrength.h>
|
||||
#include <aidl/android/hardware/biometrics/face/BnSession.h>
|
||||
#include <aidl/android/hardware/biometrics/face/FaceSensorType.h>
|
||||
#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
|
||||
|
||||
#include <random>
|
||||
|
||||
#include <future>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "FakeLockoutTracker.h"
|
||||
|
||||
namespace aidl::android::hardware::biometrics::face {
|
||||
|
||||
namespace face = aidl::android::hardware::biometrics::face;
|
||||
|
@ -39,6 +38,7 @@ using aidl::android::hardware::common::NativeHandle;
|
|||
class FakeFaceEngine {
|
||||
public:
|
||||
FakeFaceEngine() : mRandom(std::mt19937::default_seed) {}
|
||||
virtual ~FakeFaceEngine() {}
|
||||
|
||||
static face::FaceSensorType GetSensorType();
|
||||
static common::SensorStrength GetSensorStrength();
|
||||
|
@ -61,6 +61,13 @@ class FakeFaceEngine {
|
|||
void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
|
||||
void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
|
||||
|
||||
virtual std::string toString() const {
|
||||
std::ostringstream os;
|
||||
os << "----- FakeFaceEngine:: -----" << std::endl;
|
||||
os << mLockoutTracker.toString();
|
||||
return os.str();
|
||||
}
|
||||
|
||||
std::mt19937 mRandom;
|
||||
|
||||
private:
|
||||
|
@ -68,6 +75,7 @@ class FakeFaceEngine {
|
|||
static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
|
||||
std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
|
||||
std::pair<Error, int32_t> convertError(int32_t code);
|
||||
FakeLockoutTracker mLockoutTracker;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
|
|
138
biometrics/face/aidl/default/FakeLockoutTracker.cpp
Normal file
138
biometrics/face/aidl/default/FakeLockoutTracker.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (C) 2023 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 "FaceVirtualHalLockoutTracker"
|
||||
|
||||
#include "FakeLockoutTracker.h"
|
||||
#include <android-base/logging.h>
|
||||
#include <face.sysprop.h>
|
||||
#include "util/Util.h"
|
||||
|
||||
using namespace ::android::face::virt;
|
||||
|
||||
namespace aidl::android::hardware::biometrics::face {
|
||||
|
||||
void FakeLockoutTracker::reset(bool dueToTimerExpire) {
|
||||
if (!dueToTimerExpire) {
|
||||
mFailedCount = 0;
|
||||
mLastFailedTime = 0;
|
||||
}
|
||||
mTimedFailedCount = 0;
|
||||
mCurrentMode = LockoutMode::kNone;
|
||||
abortTimer();
|
||||
}
|
||||
|
||||
void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
|
||||
bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
|
||||
bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
|
||||
if (lockoutEnabled) {
|
||||
mFailedCount++;
|
||||
mTimedFailedCount++;
|
||||
mLastFailedTime = Util::getSystemNanoTime();
|
||||
int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
|
||||
int32_t lockoutPermanetThreshold =
|
||||
FaceHalProperties::lockout_permanent_threshold().value_or(5);
|
||||
if (mFailedCount >= lockoutPermanetThreshold) {
|
||||
mCurrentMode = LockoutMode::kPermanent;
|
||||
LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
|
||||
cb->onLockoutPermanent();
|
||||
abortTimer();
|
||||
} else if (timedLockoutenabled && mTimedFailedCount >= lockoutTimedThreshold) {
|
||||
if (mCurrentMode == LockoutMode::kNone) {
|
||||
mCurrentMode = LockoutMode::kTimed;
|
||||
startLockoutTimer(getTimedLockoutDuration(), cb);
|
||||
}
|
||||
LOG(ERROR) << "FakeLockoutTracker: lockoutTimed";
|
||||
cb->onLockoutTimed(getLockoutTimeLeft());
|
||||
}
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
|
||||
return mCurrentMode;
|
||||
}
|
||||
|
||||
int32_t FakeLockoutTracker::getTimedLockoutDuration() {
|
||||
return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
|
||||
}
|
||||
|
||||
int64_t FakeLockoutTracker::getLockoutTimeLeft() {
|
||||
int64_t res = 0;
|
||||
|
||||
if (mLastFailedTime > 0) {
|
||||
auto now = Util::getSystemNanoTime();
|
||||
auto elapsed = (now - mLastFailedTime) / 1000000LL;
|
||||
res = getTimedLockoutDuration() - elapsed;
|
||||
LOG(INFO) << "elapsed=" << elapsed << " now = " << now
|
||||
<< " mLastFailedTime=" << mLastFailedTime << " res=" << res;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool FakeLockoutTracker::checkIfLockout(ISessionCallback* cb) {
|
||||
if (mCurrentMode == LockoutMode::kPermanent) {
|
||||
LOG(ERROR) << "Lockout permanent";
|
||||
cb->onLockoutPermanent();
|
||||
return true;
|
||||
} else if (mCurrentMode == LockoutMode::kTimed) {
|
||||
auto timeLeft = getLockoutTimeLeft();
|
||||
LOG(ERROR) << "Lockout timed " << timeLeft;
|
||||
cb->onLockoutTimed(timeLeft);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FakeLockoutTracker::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
|
||||
LOG(ERROR) << "startLockoutTimer: to=" << timeout;
|
||||
if (mIsLockoutTimerStarted) return;
|
||||
std::function<void(ISessionCallback*)> action =
|
||||
std::bind(&FakeLockoutTracker::lockoutTimerExpired, this, std::placeholders::_1);
|
||||
std::thread([timeout, action, cb]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
|
||||
action(cb);
|
||||
}).detach();
|
||||
|
||||
mIsLockoutTimerStarted = true;
|
||||
}
|
||||
|
||||
void FakeLockoutTracker::lockoutTimerExpired(ISessionCallback* cb) {
|
||||
LOG(INFO) << "lockout timer expired";
|
||||
mIsLockoutTimerStarted = false;
|
||||
|
||||
if (mIsLockoutTimerAborted) {
|
||||
mIsLockoutTimerAborted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// if more failures seen since the timer started, need to restart timer again
|
||||
auto deltaTime = getLockoutTimeLeft();
|
||||
if (deltaTime <= 0) {
|
||||
cb->onLockoutCleared();
|
||||
reset(true);
|
||||
} else {
|
||||
startLockoutTimer(deltaTime, cb);
|
||||
}
|
||||
}
|
||||
|
||||
void FakeLockoutTracker::abortTimer() {
|
||||
if (mIsLockoutTimerStarted) mIsLockoutTimerAborted = true;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
70
biometrics/face/aidl/default/FakeLockoutTracker.h
Normal file
70
biometrics/face/aidl/default/FakeLockoutTracker.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (C) 2023 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/ISessionCallback.h>
|
||||
#include <android/binder_to_string.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace aidl::android::hardware::biometrics::face {
|
||||
|
||||
// Lockout implementation for Face Virtual HAL
|
||||
class FakeLockoutTracker {
|
||||
public:
|
||||
FakeLockoutTracker()
|
||||
: mFailedCount(0),
|
||||
mLastFailedTime(0),
|
||||
mIsLockoutTimerStarted(false),
|
||||
mIsLockoutTimerAborted(false) {}
|
||||
~FakeLockoutTracker() {}
|
||||
|
||||
enum class LockoutMode : int8_t { kNone = 0, kTimed, kPermanent };
|
||||
|
||||
bool checkIfLockout(ISessionCallback*);
|
||||
void addFailedAttempt(ISessionCallback*);
|
||||
int64_t getLockoutTimeLeft();
|
||||
LockoutMode getMode();
|
||||
void reset(bool dueToTimerExpire = false);
|
||||
inline std::string toString() const {
|
||||
std::ostringstream os;
|
||||
os << "----- FakeLockoutTracker:: -----" << std::endl;
|
||||
os << "mFailedCount:" << mFailedCount;
|
||||
os << ", mCurrentMode:" << (int)mCurrentMode;
|
||||
os << ", mLastFailedTime:" << (int)(mLastFailedTime / 1000000LL);
|
||||
os << ", mIsLockoutTimerStarted:" << mIsLockoutTimerStarted;
|
||||
os << ", mIsLockoutTimerAborted:" << mIsLockoutTimerAborted;
|
||||
os << std::endl;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
private:
|
||||
void startLockoutTimer(int64_t timeout, ISessionCallback* cb);
|
||||
void lockoutTimerExpired(ISessionCallback* cb);
|
||||
int32_t getTimedLockoutDuration();
|
||||
void abortTimer();
|
||||
|
||||
private:
|
||||
int32_t mFailedCount;
|
||||
int32_t mTimedFailedCount;
|
||||
int64_t mLastFailedTime;
|
||||
LockoutMode mCurrentMode;
|
||||
bool mIsLockoutTimerStarted;
|
||||
bool mIsLockoutTimerAborted;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
|
@ -51,31 +51,31 @@ $ adb shell cmd face syncadb shell cmd face sync
|
|||
|
||||
To authenticate successfully, the captured (hit) must match the enrollment id<br/>
|
||||
set above. To trigger authentication failure, set the hit id to a different value.
|
||||
```shell
|
||||
`shell
|
||||
$ adb shell setprop vendor.face.virtual.operation_authenticate_duration 800
|
||||
$ adb shell setprop vendor.face.virtual.enrollment_hit 1
|
||||
```
|
||||
$ adb shell setprop vendor.face.virtual.enrollment_hit 1`
|
||||
|
||||
### AcquiredInfo
|
||||
|
||||
AcquiredInfo codes can be sent during authentication by specifying the sysprop.<br/>
|
||||
The codes is sent in sequence and in the interval of operation_authentication_duration/numberOfAcquiredInfoCode
|
||||
```shell
|
||||
$ adb shell setprop vendor.face.virtual.operation_authenticate_acquired 6,9,1013
|
||||
```
|
||||
`shell
|
||||
$ adb shell setprop vendor.face.virtual.operation_authenticate_acquired 6,9,1013`
|
||||
Refer to [AcquiredInfo.aidl](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/AcquiredInfo.aidl) for full face acquiredInfo codes.
|
||||
Note: For vendor specific acquired info, acquiredInfo = 1000 + vendorCode.
|
||||
|
||||
### Error Insertion
|
||||
Error can be inserted during authentction by specifying the authenticate_error sysprop.
|
||||
```shell
|
||||
$ adb shell setprop vendor.face.virtual.operation_authenticate_error 4
|
||||
```
|
||||
Refer to [Error.aidl](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl) for full face error codes
|
||||
|
||||
Error can be inserted during authentction by specifying the authenticate_error
|
||||
sysprop. `shell $ adb shell setprop
|
||||
vendor.face.virtual.operation_authenticate_error 4` Refer to
|
||||
[Error.aidl](https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:hardware/interfaces/biometrics/face/aidl/android/hardware/biometrics/face/Error.aidl)
|
||||
for full face error codes
|
||||
|
||||
## Enrollment via Settings
|
||||
|
||||
Enrollment process is specified by sysprop `next_enrollment` in the following format
|
||||
Enrollment process is specified by sysprop `next_enrollment` in the following
|
||||
format
|
||||
|
||||
```shell
|
||||
Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
|
||||
|
@ -88,7 +88,40 @@ Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
|
|||
E.g.
|
||||
$ adb shell setprop vendor.face.virtual.next_enrollment 1:6000-[21,8,1,1108,1,10,1113,1,1118,1124]:true
|
||||
```
|
||||
|
||||
If next_enrollment prop is not set, the following default value is used:<br/>
|
||||
defaultNextEnrollment="1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true"<br/>
|
||||
Note: Enrollment data and configuration can be supported upon request in case of needs
|
||||
|
||||
## Lockout
|
||||
|
||||
Device lockout is based on the number of consecutive failed authentication attempts. There are a few
|
||||
flavors of lockout mechanisms that are supported by virtula HAL <br/>
|
||||
|
||||
### Permanent Lockout
|
||||
|
||||
There are two sysprop to control permanent lockout <br/>
|
||||
1. general lockout feature enable <br/>
|
||||
2. threshold of failed attempts <br/>
|
||||
`shell
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_enable true
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_permanent_threshold 3`
|
||||
|
||||
### Temporary Lockout
|
||||
|
||||
There are a few parameters to control temporary lockout (aka timed lockout): <br/>
|
||||
1. enable lockout (general lockout feature enable, and timed lcokout enable) <br/>
|
||||
2. threshold of failed attempts <br/>
|
||||
3. timeout in ms <br/>
|
||||
`shell
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_enable true
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_timed_enable true
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_timed_threshold 5
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout_timed_duration 10000`
|
||||
|
||||
### Forced Lockout
|
||||
|
||||
A permanent lockout can be inserted on next authentication attempt independent of the failed <br/>
|
||||
attempt count. This is a feature purely for test purpose.
|
||||
`shell
|
||||
$ adb shell setprop persist.vendor.face.virtual.lockout true`
|
||||
|
|
|
@ -92,7 +92,7 @@ prop {
|
|||
api_name: "challenge"
|
||||
}
|
||||
|
||||
# if locked out
|
||||
# if forced to lock out (Default to false)
|
||||
prop {
|
||||
prop_name: "vendor.face.virtual.lockout"
|
||||
type: Boolean
|
||||
|
@ -176,3 +176,47 @@ prop {
|
|||
api_name: "operation_authenticate_acquired"
|
||||
}
|
||||
|
||||
# whether support lockout based on the failed auth attempts (default: false)
|
||||
prop {
|
||||
prop_name: "persist.vendor.face.virtual.lockout_enable"
|
||||
type: Boolean
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "lockout_enable"
|
||||
}
|
||||
|
||||
# whether support timed_lockout based on the failed auth attempts (default: false)
|
||||
prop {
|
||||
prop_name: "persist.vendor.face.virtual.lockout_timed_enable"
|
||||
type: Boolean
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "lockout_timed_enable"
|
||||
}
|
||||
|
||||
# temperory lockout threshold in number of consecutive failed auth attempts
|
||||
prop {
|
||||
prop_name: "persist.vendor.face.virtual.lockout_timed_threshold"
|
||||
type: Integer
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "lockout_timed_threshold"
|
||||
}
|
||||
|
||||
# temporary lockout duration in ms (default: 10000ms)
|
||||
prop {
|
||||
prop_name: "persist.vendor.face.virtual.lockout_timed_duration"
|
||||
type: Integer
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "lockout_timed_duration"
|
||||
}
|
||||
|
||||
# permanently lockout threshold in number of consecutive failed auth attempts
|
||||
prop {
|
||||
prop_name: "persist.vendor.face.virtual.lockout_permanent_threshold"
|
||||
type: Integer
|
||||
scope: Internal
|
||||
access: ReadWrite
|
||||
api_name: "lockout_permanent_threshold"
|
||||
}
|
||||
|
|
216
biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
Normal file
216
biometrics/face/aidl/default/tests/FakeLockoutTrackerTest.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (C) 2023 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 <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
|
||||
#include <android/binder_process.h>
|
||||
#include <face.sysprop.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "FakeLockoutTracker.h"
|
||||
#include "util/Util.h"
|
||||
|
||||
using namespace ::android::face::virt;
|
||||
using namespace ::aidl::android::hardware::biometrics::face;
|
||||
|
||||
namespace aidl::android::hardware::biometrics::face {
|
||||
|
||||
class TestSessionCallback : public BnSessionCallback {
|
||||
public:
|
||||
ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onError(face::Error, int32_t /*vendorCode*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
|
||||
int32_t /*remaining*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
|
||||
const keymaster::HardwareAuthToken&) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); };
|
||||
::ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); };
|
||||
::ndk::ScopedAStatus onEnrollmentsEnumerated(const std::vector<int32_t>&) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onEnrollmentsRemoved(
|
||||
const std::vector<int32_t>& /*enrollmentIds*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame&) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>&) {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onFeatureSet(Feature) override { return ndk::ScopedAStatus::ok(); }
|
||||
::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
|
||||
::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame&) override {
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus onLockoutTimed(int64_t timeLeft) override {
|
||||
mLockoutTimed++;
|
||||
mTimeLeft = timeLeft;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onLockoutPermanent() override {
|
||||
mLockoutPermanent++;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
::ndk::ScopedAStatus onLockoutCleared() override {
|
||||
mTimeLeft = 0;
|
||||
mLockoutTimed = 0;
|
||||
mLockoutPermanent = 0;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
};
|
||||
|
||||
int64_t mTimeLeft = 0;
|
||||
int mLockoutTimed = 0;
|
||||
int mLockoutPermanent = 0;
|
||||
};
|
||||
|
||||
class FakeLockoutTrackerTest : public ::testing::Test {
|
||||
protected:
|
||||
static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
|
||||
static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
FakeLockoutTracker mLockoutTracker;
|
||||
std::shared_ptr<TestSessionCallback> mCallback;
|
||||
};
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
|
||||
FaceHalProperties::lockout_enable(false);
|
||||
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
|
||||
ASSERT_EQ(0, mCallback->mLockoutTimed);
|
||||
}
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
|
||||
FaceHalProperties::lockout_enable(true);
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
|
||||
ASSERT_EQ(0, mCallback->mLockoutPermanent);
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
|
||||
ASSERT_EQ(1, mCallback->mLockoutPermanent);
|
||||
ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
ASSERT_EQ(2, mCallback->mLockoutPermanent);
|
||||
}
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
|
||||
FaceHalProperties::lockout_enable(true);
|
||||
FaceHalProperties::lockout_timed_enable(true);
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
|
||||
ASSERT_EQ(1, mCallback->mLockoutTimed);
|
||||
ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
ASSERT_EQ(2, mCallback->mLockoutTimed);
|
||||
// time left
|
||||
int N = 5;
|
||||
int64_t prevTimeLeft = INT_MAX;
|
||||
for (int i = 0; i < N; i++) {
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
|
||||
int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
|
||||
ASSERT_TRUE(currTimeLeft < prevTimeLeft);
|
||||
prevTimeLeft = currTimeLeft;
|
||||
}
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION / N);
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
|
||||
}
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
|
||||
FaceHalProperties::lockout_enable(true);
|
||||
FaceHalProperties::lockout_timed_enable(true);
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION + 20);
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
|
||||
for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - LOCKOUT_TIMED_THRESHOLD; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
|
||||
}
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
|
||||
FaceHalProperties::lockout_enable(true);
|
||||
FaceHalProperties::lockout_timed_enable(true);
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
ASSERT_EQ(0, mCallback->mLockoutTimed);
|
||||
for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION / 2);
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION);
|
||||
ASSERT_EQ(2, mCallback->mLockoutTimed);
|
||||
ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
SLEEP_MS(LOCKOUT_TIMED_DURATION);
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
}
|
||||
|
||||
TEST_F(FakeLockoutTrackerTest, resetLockout) {
|
||||
FaceHalProperties::lockout_enable(true);
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
|
||||
for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
|
||||
mLockoutTracker.addFailedAttempt(mCallback.get());
|
||||
ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
|
||||
mLockoutTracker.reset();
|
||||
ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::biometrics::face
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
ABinderProcess_startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in a new issue