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 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
18 #include <android/binder_process.h>
19 #include <face.sysprop.h>
20 #include <gtest/gtest.h>
21
22 #include <android-base/logging.h>
23
24 #include "FakeLockoutTracker.h"
25 #include "util/Util.h"
26
27 using namespace ::android::face::virt;
28 using namespace ::aidl::android::hardware::biometrics::face;
29
30 namespace aidl::android::hardware::biometrics::face {
31
32 class TestSessionCallback : public BnSessionCallback {
33 public:
onChallengeGenerated(int64_t)34 ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
35 return ndk::ScopedAStatus::ok();
36 };
onChallengeRevoked(int64_t)37 ::ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
38 return ndk::ScopedAStatus::ok();
39 };
onError(face::Error,int32_t)40 ::ndk::ScopedAStatus onError(face::Error, int32_t /*vendorCode*/) override {
41 return ndk::ScopedAStatus::ok();
42 };
onEnrollmentProgress(int32_t,int32_t)43 ::ndk::ScopedAStatus onEnrollmentProgress(int32_t /*enrollmentId*/,
44 int32_t /*remaining*/) override {
45 return ndk::ScopedAStatus::ok();
46 };
onAuthenticationSucceeded(int32_t,const keymaster::HardwareAuthToken &)47 ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t /*enrollmentId*/,
48 const keymaster::HardwareAuthToken&) override {
49 return ndk::ScopedAStatus::ok();
50 };
onAuthenticationFailed()51 ::ndk::ScopedAStatus onAuthenticationFailed() override { return ndk::ScopedAStatus::ok(); };
onInteractionDetected()52 ::ndk::ScopedAStatus onInteractionDetected() override { return ndk::ScopedAStatus::ok(); };
onEnrollmentsEnumerated(const std::vector<int32_t> &)53 ::ndk::ScopedAStatus onEnrollmentsEnumerated(const std::vector<int32_t>&) override {
54 return ndk::ScopedAStatus::ok();
55 };
onEnrollmentsRemoved(const std::vector<int32_t> &)56 ::ndk::ScopedAStatus onEnrollmentsRemoved(
57 const std::vector<int32_t>& /*enrollmentIds*/) override {
58 return ndk::ScopedAStatus::ok();
59 };
onAuthenticatorIdRetrieved(int64_t)60 ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
61 return ndk::ScopedAStatus::ok();
62 };
onAuthenticatorIdInvalidated(int64_t)63 ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*authenticatorId*/) override {
64 return ndk::ScopedAStatus::ok();
65 };
onEnrollmentFrame(const EnrollmentFrame &)66 ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame&) override {
67 return ndk::ScopedAStatus::ok();
68 }
onFeaturesRetrieved(const std::vector<Feature> &)69 ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>&) {
70 return ndk::ScopedAStatus::ok();
71 };
onFeatureSet(Feature)72 ::ndk::ScopedAStatus onFeatureSet(Feature) override { return ndk::ScopedAStatus::ok(); }
onSessionClosed()73 ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
onAuthenticationFrame(const AuthenticationFrame &)74 ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame&) override {
75 return ndk::ScopedAStatus::ok();
76 }
77
onLockoutTimed(int64_t timeLeft)78 ndk::ScopedAStatus onLockoutTimed(int64_t timeLeft) override {
79 mLockoutTimed++;
80 mTimeLeft = timeLeft;
81 return ndk::ScopedAStatus::ok();
82 };
onLockoutPermanent()83 ::ndk::ScopedAStatus onLockoutPermanent() override {
84 mLockoutPermanent++;
85 return ndk::ScopedAStatus::ok();
86 };
onLockoutCleared()87 ::ndk::ScopedAStatus onLockoutCleared() override {
88 mTimeLeft = 0;
89 mLockoutTimed = 0;
90 mLockoutPermanent = 0;
91 return ndk::ScopedAStatus::ok();
92 };
93
94 int64_t mTimeLeft = 0;
95 int mLockoutTimed = 0;
96 int mLockoutPermanent = 0;
97 };
98
99 class FakeLockoutTrackerTest : public ::testing::Test {
100 protected:
101 static constexpr int32_t LOCKOUT_TIMED_THRESHOLD = 3;
102 static constexpr int32_t LOCKOUT_PERMANENT_THRESHOLD = 5;
103 static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
104
SetUp()105 void SetUp() override {
106 FaceHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
107 FaceHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
108 FaceHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
109 mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
110 }
111
TearDown()112 void TearDown() override {
113 // reset to default
114 FaceHalProperties::lockout_timed_threshold(5);
115 FaceHalProperties::lockout_timed_duration(20);
116 FaceHalProperties::lockout_permanent_threshold(10000);
117 FaceHalProperties::lockout_enable(false);
118 FaceHalProperties::lockout(false);
119 }
120
121 FakeLockoutTracker mLockoutTracker;
122 std::shared_ptr<TestSessionCallback> mCallback;
123 };
124
TEST_F(FakeLockoutTrackerTest,addFailedAttemptDisable)125 TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
126 FaceHalProperties::lockout_enable(false);
127 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++)
128 mLockoutTracker.addFailedAttempt(mCallback.get());
129 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
130 ASSERT_EQ(0, mCallback->mLockoutTimed);
131 }
132
TEST_F(FakeLockoutTrackerTest,addFailedAttemptPermanent)133 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
134 FaceHalProperties::lockout_enable(true);
135 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
136 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++)
137 mLockoutTracker.addFailedAttempt(mCallback.get());
138 ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
139 ASSERT_EQ(0, mCallback->mLockoutPermanent);
140 mLockoutTracker.addFailedAttempt(mCallback.get());
141 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
142 ASSERT_EQ(1, mCallback->mLockoutPermanent);
143 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
144 ASSERT_EQ(2, mCallback->mLockoutPermanent);
145 }
146
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockoutTimed)147 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
148 FaceHalProperties::lockout_enable(true);
149 FaceHalProperties::lockout_timed_enable(true);
150 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
151 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
152 mLockoutTracker.addFailedAttempt(mCallback.get());
153 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
154 ASSERT_EQ(1, mCallback->mLockoutTimed);
155 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
156 ASSERT_EQ(2, mCallback->mLockoutTimed);
157 // time left
158 int N = 5;
159 int64_t prevTimeLeft = INT_MAX;
160 for (int i = 0; i < N; i++) {
161 SLEEP_MS(LOCKOUT_TIMED_DURATION / N + 1);
162 int64_t currTimeLeft = mLockoutTracker.getLockoutTimeLeft();
163 ASSERT_TRUE(currTimeLeft < prevTimeLeft);
164 prevTimeLeft = currTimeLeft;
165 }
166 SLEEP_MS(LOCKOUT_TIMED_DURATION / N);
167 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
168 }
169
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockout_TimedThenPermanent)170 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockout_TimedThenPermanent) {
171 FaceHalProperties::lockout_enable(true);
172 FaceHalProperties::lockout_timed_enable(true);
173 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
174 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
175 mLockoutTracker.addFailedAttempt(mCallback.get());
176 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
177 SLEEP_MS(LOCKOUT_TIMED_DURATION + 20);
178 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
179 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - LOCKOUT_TIMED_THRESHOLD; i++)
180 mLockoutTracker.addFailedAttempt(mCallback.get());
181 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
182 }
183
TEST_F(FakeLockoutTrackerTest,addFailedAttemptLockoutTimedTwice)184 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimedTwice) {
185 FaceHalProperties::lockout_enable(true);
186 FaceHalProperties::lockout_timed_enable(true);
187 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
188 ASSERT_EQ(0, mCallback->mLockoutTimed);
189 for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++)
190 mLockoutTracker.addFailedAttempt(mCallback.get());
191 SLEEP_MS(LOCKOUT_TIMED_DURATION / 2);
192 mLockoutTracker.addFailedAttempt(mCallback.get());
193 SLEEP_MS(LOCKOUT_TIMED_DURATION);
194 ASSERT_EQ(2, mCallback->mLockoutTimed);
195 ASSERT_TRUE(mLockoutTracker.checkIfLockout(mCallback.get()));
196 SLEEP_MS(LOCKOUT_TIMED_DURATION);
197 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
198 }
199
TEST_F(FakeLockoutTrackerTest,resetLockout)200 TEST_F(FakeLockoutTrackerTest, resetLockout) {
201 FaceHalProperties::lockout_enable(true);
202 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
203 for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD; i++)
204 mLockoutTracker.addFailedAttempt(mCallback.get());
205 ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
206 mLockoutTracker.reset();
207 ASSERT_FALSE(mLockoutTracker.checkIfLockout(mCallback.get()));
208 }
209
210 } // namespace aidl::android::hardware::biometrics::face
211
main(int argc,char ** argv)212 int main(int argc, char** argv) {
213 testing::InitGoogleTest(&argc, argv);
214 ABinderProcess_startThreadPool();
215 return RUN_ALL_TESTS();
216 }
217