1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "FaceVirtualHalLockoutTracker"
18
19 #include "FakeLockoutTracker.h"
20 #include <android-base/logging.h>
21 #include <face.sysprop.h>
22 #include "util/Util.h"
23
24 using namespace ::android::face::virt;
25
26 namespace aidl::android::hardware::biometrics::face {
27
reset(bool dueToTimerExpire)28 void FakeLockoutTracker::reset(bool dueToTimerExpire) {
29 if (!dueToTimerExpire) {
30 mFailedCount = 0;
31 mLastFailedTime = 0;
32 }
33 mTimedFailedCount = 0;
34 mCurrentMode = LockoutMode::kNone;
35 abortTimer();
36 }
37
addFailedAttempt(ISessionCallback * cb)38 void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
39 bool lockoutEnabled = FaceHalProperties::lockout_enable().value_or(false);
40 bool timedLockoutenabled = FaceHalProperties::lockout_timed_enable().value_or(false);
41 if (lockoutEnabled) {
42 mFailedCount++;
43 mTimedFailedCount++;
44 mLastFailedTime = Util::getSystemNanoTime();
45 int32_t lockoutTimedThreshold = FaceHalProperties::lockout_timed_threshold().value_or(3);
46 int32_t lockoutPermanetThreshold =
47 FaceHalProperties::lockout_permanent_threshold().value_or(5);
48 if (mFailedCount >= lockoutPermanetThreshold) {
49 mCurrentMode = LockoutMode::kPermanent;
50 LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
51 cb->onLockoutPermanent();
52 abortTimer();
53 } else if (timedLockoutenabled && mTimedFailedCount >= lockoutTimedThreshold) {
54 if (mCurrentMode == LockoutMode::kNone) {
55 mCurrentMode = LockoutMode::kTimed;
56 startLockoutTimer(getTimedLockoutDuration(), cb);
57 }
58 LOG(ERROR) << "FakeLockoutTracker: lockoutTimed";
59 cb->onLockoutTimed(getLockoutTimeLeft());
60 }
61 } else {
62 reset();
63 }
64 }
65
getMode()66 FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
67 return mCurrentMode;
68 }
69
getTimedLockoutDuration()70 int32_t FakeLockoutTracker::getTimedLockoutDuration() {
71 return FaceHalProperties::lockout_timed_duration().value_or(10 * 1000);
72 }
73
getLockoutTimeLeft()74 int64_t FakeLockoutTracker::getLockoutTimeLeft() {
75 int64_t res = 0;
76
77 if (mLastFailedTime > 0) {
78 auto now = Util::getSystemNanoTime();
79 auto elapsed = (now - mLastFailedTime) / 1000000LL;
80 res = getTimedLockoutDuration() - elapsed;
81 LOG(INFO) << "elapsed=" << elapsed << " now = " << now
82 << " mLastFailedTime=" << mLastFailedTime << " res=" << res;
83 }
84
85 return res;
86 }
87
checkIfLockout(ISessionCallback * cb)88 bool FakeLockoutTracker::checkIfLockout(ISessionCallback* cb) {
89 if (mCurrentMode == LockoutMode::kPermanent) {
90 LOG(ERROR) << "Lockout permanent";
91 cb->onLockoutPermanent();
92 return true;
93 } else if (mCurrentMode == LockoutMode::kTimed) {
94 auto timeLeft = getLockoutTimeLeft();
95 LOG(ERROR) << "Lockout timed " << timeLeft;
96 cb->onLockoutTimed(timeLeft);
97 return true;
98 }
99 return false;
100 }
101
startLockoutTimer(int64_t timeout,ISessionCallback * cb)102 void FakeLockoutTracker::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
103 LOG(ERROR) << "startLockoutTimer: to=" << timeout;
104 if (mIsLockoutTimerStarted) return;
105 std::function<void(ISessionCallback*)> action =
106 std::bind(&FakeLockoutTracker::lockoutTimerExpired, this, std::placeholders::_1);
107 std::thread([timeout, action, cb]() {
108 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
109 action(cb);
110 }).detach();
111
112 mIsLockoutTimerStarted = true;
113 }
114
lockoutTimerExpired(ISessionCallback * cb)115 void FakeLockoutTracker::lockoutTimerExpired(ISessionCallback* cb) {
116 LOG(INFO) << "lockout timer expired";
117 mIsLockoutTimerStarted = false;
118
119 if (mIsLockoutTimerAborted) {
120 mIsLockoutTimerAborted = false;
121 return;
122 }
123
124 // if more failures seen since the timer started, need to restart timer again
125 auto deltaTime = getLockoutTimeLeft();
126 if (deltaTime <= 0) {
127 cb->onLockoutCleared();
128 reset(true);
129 } else {
130 startLockoutTimer(deltaTime, cb);
131 }
132 }
133
abortTimer()134 void FakeLockoutTracker::abortTimer() {
135 if (mIsLockoutTimerStarted) mIsLockoutTimerAborted = true;
136 }
137
138 } // namespace aidl::android::hardware::biometrics::face
139