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