/* * 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 #include #include "Face.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 = Face::cfg().get("lockout_enable"); bool timedLockoutenabled = Face::cfg().get("lockout_timed_enable"); if (lockoutEnabled) { mFailedCount++; mTimedFailedCount++; mLastFailedTime = Util::getSystemNanoTime(); int32_t lockoutTimedThreshold = Face::cfg().get("lockout_timed_threshold"); int32_t lockoutPermanetThreshold = Face::cfg().get("lockout_permanent_threshold"); 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 Face::cfg().get("lockout_timed_duration"); } 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 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