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 "Face.h"
23 #include "util/Util.h"
24
25 using namespace ::android::face::virt;
26
27 namespace aidl::android::hardware::biometrics::face {
28
reset(bool dueToTimerExpire)29 void FakeLockoutTracker::reset(bool dueToTimerExpire) {
30 if (!dueToTimerExpire) {
31 mFailedCount = 0;
32 mLastFailedTime = 0;
33 }
34 mTimedFailedCount = 0;
35 mCurrentMode = LockoutMode::kNone;
36 abortTimer();
37 }
38
addFailedAttempt(ISessionCallback * cb)39 void FakeLockoutTracker::addFailedAttempt(ISessionCallback* cb) {
40 bool lockoutEnabled = Face::cfg().get<bool>("lockout_enable");
41 bool timedLockoutenabled = Face::cfg().get<bool>("lockout_timed_enable");
42 if (lockoutEnabled) {
43 mFailedCount++;
44 mTimedFailedCount++;
45 mLastFailedTime = Util::getSystemNanoTime();
46 int32_t lockoutTimedThreshold = Face::cfg().get<std::int32_t>("lockout_timed_threshold");
47 int32_t lockoutPermanetThreshold =
48 Face::cfg().get<std::int32_t>("lockout_permanent_threshold");
49 if (mFailedCount >= lockoutPermanetThreshold) {
50 mCurrentMode = LockoutMode::kPermanent;
51 LOG(ERROR) << "FakeLockoutTracker: lockoutPermanent";
52 cb->onLockoutPermanent();
53 abortTimer();
54 } else if (timedLockoutenabled && mTimedFailedCount >= lockoutTimedThreshold) {
55 if (mCurrentMode == LockoutMode::kNone) {
56 mCurrentMode = LockoutMode::kTimed;
57 startLockoutTimer(getTimedLockoutDuration(), cb);
58 }
59 LOG(ERROR) << "FakeLockoutTracker: lockoutTimed";
60 cb->onLockoutTimed(getLockoutTimeLeft());
61 }
62 } else {
63 reset();
64 }
65 }
66
getMode()67 FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
68 return mCurrentMode;
69 }
70
getTimedLockoutDuration()71 int32_t FakeLockoutTracker::getTimedLockoutDuration() {
72 return Face::cfg().get<std::int32_t>("lockout_timed_duration");
73 }
74
getLockoutTimeLeft()75 int64_t FakeLockoutTracker::getLockoutTimeLeft() {
76 int64_t res = 0;
77
78 if (mLastFailedTime > 0) {
79 auto now = Util::getSystemNanoTime();
80 auto elapsed = (now - mLastFailedTime) / 1000000LL;
81 res = getTimedLockoutDuration() - elapsed;
82 LOG(INFO) << "elapsed=" << elapsed << " now = " << now
83 << " mLastFailedTime=" << mLastFailedTime << " res=" << res;
84 }
85
86 return res;
87 }
88
checkIfLockout(ISessionCallback * cb)89 bool FakeLockoutTracker::checkIfLockout(ISessionCallback* cb) {
90 if (mCurrentMode == LockoutMode::kPermanent) {
91 LOG(ERROR) << "Lockout permanent";
92 cb->onLockoutPermanent();
93 return true;
94 } else if (mCurrentMode == LockoutMode::kTimed) {
95 auto timeLeft = getLockoutTimeLeft();
96 LOG(ERROR) << "Lockout timed " << timeLeft;
97 cb->onLockoutTimed(timeLeft);
98 return true;
99 }
100 return false;
101 }
102
startLockoutTimer(int64_t timeout,ISessionCallback * cb)103 void FakeLockoutTracker::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
104 LOG(ERROR) << "startLockoutTimer: to=" << timeout;
105 if (mIsLockoutTimerStarted) return;
106 std::function<void(ISessionCallback*)> action =
107 std::bind(&FakeLockoutTracker::lockoutTimerExpired, this, std::placeholders::_1);
108 std::thread([timeout, action, cb]() {
109 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
110 action(cb);
111 }).detach();
112
113 mIsLockoutTimerStarted = true;
114 }
115
lockoutTimerExpired(ISessionCallback * cb)116 void FakeLockoutTracker::lockoutTimerExpired(ISessionCallback* cb) {
117 LOG(INFO) << "lockout timer expired";
118 mIsLockoutTimerStarted = false;
119
120 if (mIsLockoutTimerAborted) {
121 mIsLockoutTimerAborted = false;
122 return;
123 }
124
125 // if more failures seen since the timer started, need to restart timer again
126 auto deltaTime = getLockoutTimeLeft();
127 if (deltaTime <= 0) {
128 cb->onLockoutCleared();
129 reset(true);
130 } else {
131 startLockoutTimer(deltaTime, cb);
132 }
133 }
134
abortTimer()135 void FakeLockoutTracker::abortTimer() {
136 if (mIsLockoutTimerStarted) mIsLockoutTimerAborted = true;
137 }
138
139 } // namespace aidl::android::hardware::biometrics::face
140