• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 "FakeFingerprintEngine.h"
18 #include <regex>
19 #include "Fingerprint.h"
20 
21 #include <android-base/logging.h>
22 #include <android-base/parseint.h>
23 
24 #include <fingerprint.sysprop.h>
25 
26 #include "util/CancellationSignal.h"
27 #include "util/Util.h"
28 
29 using namespace ::android::fingerprint::virt;
30 using ::android::base::ParseInt;
31 
32 namespace aidl::android::hardware::biometrics::fingerprint {
33 
FakeFingerprintEngine()34 FakeFingerprintEngine::FakeFingerprintEngine()
35     : mRandom(std::mt19937::default_seed), mWorkMode(WorkMode::kIdle) {}
36 
generateChallengeImpl(ISessionCallback * cb)37 void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
38     BEGIN_OP(0);
39     std::uniform_int_distribution<int64_t> dist;
40     auto challenge = dist(mRandom);
41     FingerprintHalProperties::challenge(challenge);
42     cb->onChallengeGenerated(challenge);
43 }
44 
revokeChallengeImpl(ISessionCallback * cb,int64_t challenge)45 void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
46     BEGIN_OP(0);
47     FingerprintHalProperties::challenge({});
48     cb->onChallengeRevoked(challenge);
49 }
50 
enrollImpl(ISessionCallback * cb,const keymaster::HardwareAuthToken & hat,const std::future<void> & cancel)51 void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
52                                        const keymaster::HardwareAuthToken& hat,
53                                        const std::future<void>& cancel) {
54     BEGIN_OP(0);
55 
56     // Do proper HAT verification in the real implementation.
57     if (hat.mac.empty()) {
58         LOG(ERROR) << "Fail: hat";
59         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
60         return;
61     }
62 
63     updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
64 }
65 
authenticateImpl(ISessionCallback * cb,int64_t operationId,const std::future<void> & cancel)66 void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId,
67                                              const std::future<void>& cancel) {
68     BEGIN_OP(0);
69     updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
70                   keymaster::HardwareAuthToken());
71 }
72 
detectInteractionImpl(ISessionCallback * cb,const std::future<void> & cancel)73 void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
74                                                   const std::future<void>& cancel) {
75     BEGIN_OP(0);
76 
77     auto detectInteractionSupported =
78             FingerprintHalProperties::detect_interaction().value_or(false);
79     if (!detectInteractionSupported) {
80         LOG(ERROR) << "Detect interaction is not supported";
81         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
82         return;
83     }
84 
85     updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
86                   keymaster::HardwareAuthToken());
87 }
88 
updateContext(WorkMode mode,ISessionCallback * cb,std::future<void> & cancel,int64_t operationId,const keymaster::HardwareAuthToken & hat)89 void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb,
90                                           std::future<void>& cancel, int64_t operationId,
91                                           const keymaster::HardwareAuthToken& hat) {
92     mCancel = std::move(cancel);
93     mWorkMode = mode;
94     mCb = cb;
95     mOperationId = operationId;
96     mHat = hat;
97 }
98 
fingerDownAction()99 void FakeFingerprintEngine::fingerDownAction() {
100     bool isTerminal = false;
101     LOG(INFO) << __func__;
102     switch (mWorkMode) {
103         case WorkMode::kAuthenticate:
104             isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel);
105             break;
106         case WorkMode::kEnroll:
107             isTerminal = onEnrollFingerDown(mCb, mHat, mCancel);
108             break;
109         case WorkMode::kDetectInteract:
110             isTerminal = onDetectInteractFingerDown(mCb, mCancel);
111             break;
112         default:
113             LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode;
114             break;
115     }
116 
117     if (isTerminal) {
118         mWorkMode = WorkMode::kIdle;
119     }
120 }
121 
onEnrollFingerDown(ISessionCallback * cb,const keymaster::HardwareAuthToken &,const std::future<void> & cancel)122 bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
123                                                const keymaster::HardwareAuthToken&,
124                                                const std::future<void>& cancel) {
125     BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
126 
127     // Force error-out
128     auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
129     if (err != 0) {
130         LOG(ERROR) << "Fail: operation_enroll_error";
131         auto ec = convertError(err);
132         cb->onError(ec.first, ec.second);
133         return true;
134     }
135 
136     // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
137     auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
138     auto parts = Util::split(nextEnroll, ":");
139     if (parts.size() != 3) {
140         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
141         cb->onError(Error::VENDOR, 0 /* vendorError */);
142         return true;
143     }
144     auto enrollmentId = std::stoi(parts[0]);
145     auto progress = parseEnrollmentCapture(parts[1]);
146     for (size_t i = 0; i < progress.size(); i += 2) {
147         auto left = (progress.size() - i) / 2 - 1;
148         auto duration = progress[i][0];
149         auto acquired = progress[i + 1];
150         auto N = acquired.size();
151 
152         for (int j = 0; j < N; j++) {
153             SLEEP_MS(duration / N);
154 
155             if (shouldCancel(cancel)) {
156                 LOG(ERROR) << "Fail: cancel";
157                 cb->onError(Error::CANCELED, 0 /* vendorCode */);
158                 return true;
159             }
160             auto ac = convertAcquiredInfo(acquired[j]);
161             cb->onAcquired(ac.first, ac.second);
162         }
163 
164         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
165             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
166             FingerprintHalProperties::next_enrollment({});
167             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
168         } else {  // progress and update props if last time
169             LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
170             if (left == 0) {
171                 auto enrollments = FingerprintHalProperties::enrollments();
172                 enrollments.emplace_back(enrollmentId);
173                 FingerprintHalProperties::enrollments(enrollments);
174                 FingerprintHalProperties::next_enrollment({});
175                 // change authenticatorId after new enrollment
176                 auto id = FingerprintHalProperties::authenticator_id().value_or(0);
177                 auto newId = id + 1;
178                 FingerprintHalProperties::authenticator_id(newId);
179                 LOG(INFO) << "Enrolled: " << enrollmentId;
180             }
181             cb->onEnrollmentProgress(enrollmentId, left);
182         }
183     }
184 
185     return true;
186 }
187 
onAuthenticateFingerDown(ISessionCallback * cb,int64_t,const std::future<void> & cancel)188 bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
189                                                      int64_t /* operationId */,
190                                                      const std::future<void>& cancel) {
191     BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
192 
193     int64_t now = Util::getSystemNanoTime();
194     int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
195     auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
196     auto acquiredInfos = parseIntSequence(acquired);
197     int N = acquiredInfos.size();
198 
199     if (N == 0) {
200         LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
201         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
202         return true;
203     }
204 
205     // got lockout?
206     if (checkSensorLockout(cb)) {
207         return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode();
208     }
209 
210     int i = 0;
211     do {
212         if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
213             LOG(ERROR) << "Fail: operation_authenticate_fails";
214             mLockoutTracker.addFailedAttempt();
215             cb->onAuthenticationFailed();
216             return false;
217         }
218 
219         auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
220         if (err != 0) {
221             LOG(ERROR) << "Fail: operation_authenticate_error";
222             auto ec = convertError(err);
223             cb->onError(ec.first, ec.second);
224             return true; /* simply terminating current operation for any user inserted error,
225                             revisit if tests need*/
226         }
227 
228         if (FingerprintHalProperties::lockout().value_or(false)) {
229             LOG(ERROR) << "Fail: lockout";
230             cb->onLockoutPermanent();
231             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
232             return true;
233         }
234 
235         if (shouldCancel(cancel)) {
236             LOG(ERROR) << "Fail: cancel";
237             cb->onError(Error::CANCELED, 0 /* vendorCode */);
238             return true;
239         }
240 
241         if (i < N) {
242             auto ac = convertAcquiredInfo(acquiredInfos[i]);
243             cb->onAcquired(ac.first, ac.second);
244             i++;
245         }
246 
247         SLEEP_MS(duration / N);
248     } while (!Util::hasElapsed(now, duration));
249 
250     auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
251     auto enrolls = FingerprintHalProperties::enrollments();
252     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
253     if (id > 0 && isEnrolled) {
254         cb->onAuthenticationSucceeded(id, {} /* hat */);
255         mLockoutTracker.reset();
256         return true;
257     } else {
258         LOG(ERROR) << "Fail: fingerprint not enrolled";
259         cb->onAuthenticationFailed();
260         mLockoutTracker.addFailedAttempt();
261         checkSensorLockout(cb);
262         return false;
263     }
264 }
265 
onDetectInteractFingerDown(ISessionCallback * cb,const std::future<void> & cancel)266 bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
267                                                        const std::future<void>& cancel) {
268     BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
269 
270     int64_t duration =
271             FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
272 
273     auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
274     auto acquiredInfos = parseIntSequence(acquired);
275     int N = acquiredInfos.size();
276     int64_t now = Util::getSystemNanoTime();
277 
278     if (N == 0) {
279         LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
280         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
281         return true;
282     }
283 
284     int i = 0;
285     do {
286         auto err = FingerprintHalProperties::operation_detect_interaction_error().value_or(0);
287         if (err != 0) {
288             LOG(ERROR) << "Fail: operation_detect_interaction_error";
289             auto ec = convertError(err);
290             cb->onError(ec.first, ec.second);
291             return true;
292         }
293 
294         if (shouldCancel(cancel)) {
295             LOG(ERROR) << "Fail: cancel";
296             cb->onError(Error::CANCELED, 0 /* vendorCode */);
297             return true;
298         }
299 
300         if (i < N) {
301             auto ac = convertAcquiredInfo(acquiredInfos[i]);
302             cb->onAcquired(ac.first, ac.second);
303             i++;
304         }
305         SLEEP_MS(duration / N);
306     } while (!Util::hasElapsed(now, duration));
307 
308     auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
309     auto enrolls = FingerprintHalProperties::enrollments();
310     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
311     if (id <= 0 || !isEnrolled) {
312         LOG(ERROR) << "Fail: not enrolled";
313         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
314         return true;
315     }
316 
317     cb->onInteractionDetected();
318 
319     return true;
320 }
321 
enumerateEnrollmentsImpl(ISessionCallback * cb)322 void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
323     BEGIN_OP(0);
324 
325     std::vector<int32_t> ids;
326     for (auto& enrollment : FingerprintHalProperties::enrollments()) {
327         auto id = enrollment.value_or(0);
328         if (id > 0) {
329             ids.push_back(id);
330         }
331     }
332 
333     cb->onEnrollmentsEnumerated(ids);
334 }
335 
removeEnrollmentsImpl(ISessionCallback * cb,const std::vector<int32_t> & enrollmentIds)336 void FakeFingerprintEngine::removeEnrollmentsImpl(ISessionCallback* cb,
337                                                   const std::vector<int32_t>& enrollmentIds) {
338     BEGIN_OP(0);
339 
340     std::vector<std::optional<int32_t>> newEnrollments;
341     std::vector<int32_t> removed;
342     for (auto& enrollment : FingerprintHalProperties::enrollments()) {
343         auto id = enrollment.value_or(0);
344         if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) != enrollmentIds.end()) {
345             removed.push_back(id);
346         } else if (id > 0) {
347             newEnrollments.emplace_back(id);
348         }
349     }
350     FingerprintHalProperties::enrollments(newEnrollments);
351 
352     cb->onEnrollmentsRemoved(enrollmentIds);
353 }
354 
getAuthenticatorIdImpl(ISessionCallback * cb)355 void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
356     BEGIN_OP(0);
357     int64_t authenticatorId;
358     if (FingerprintHalProperties::enrollments().size() == 0) {
359         authenticatorId = 0;
360     } else {
361         authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
362         if (authenticatorId == 0) authenticatorId = 1;
363     }
364     cb->onAuthenticatorIdRetrieved(authenticatorId);
365 }
366 
invalidateAuthenticatorIdImpl(ISessionCallback * cb)367 void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
368     BEGIN_OP(0);
369     int64_t newId;
370     if (FingerprintHalProperties::enrollments().size() == 0) {
371         newId = 0;
372     } else {
373         auto id = FingerprintHalProperties::authenticator_id().value_or(0);
374         newId = id + 1;
375     }
376     FingerprintHalProperties::authenticator_id(newId);
377     cb->onAuthenticatorIdInvalidated(newId);
378 }
379 
resetLockoutImpl(ISessionCallback * cb,const keymaster::HardwareAuthToken & hat)380 void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
381                                              const keymaster::HardwareAuthToken& hat) {
382     BEGIN_OP(0);
383     if (hat.mac.empty()) {
384         LOG(ERROR) << "Fail: hat in resetLockout()";
385         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
386         return;
387     }
388     clearLockout(cb);
389     isLockoutTimerAborted = true;
390 }
391 
clearLockout(ISessionCallback * cb)392 void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
393     FingerprintHalProperties::lockout(false);
394     cb->onLockoutCleared();
395     mLockoutTracker.reset();
396 }
397 
onPointerDownImpl(int32_t,int32_t,int32_t,float,float)398 ndk::ScopedAStatus FakeFingerprintEngine::onPointerDownImpl(int32_t /*pointerId*/, int32_t /*x*/,
399                                                             int32_t /*y*/, float /*minor*/,
400                                                             float /*major*/) {
401     BEGIN_OP(0);
402     fingerDownAction();
403     return ndk::ScopedAStatus::ok();
404 }
405 
onPointerUpImpl(int32_t)406 ndk::ScopedAStatus FakeFingerprintEngine::onPointerUpImpl(int32_t /*pointerId*/) {
407     BEGIN_OP(0);
408     return ndk::ScopedAStatus::ok();
409 }
410 
onUiReadyImpl()411 ndk::ScopedAStatus FakeFingerprintEngine::onUiReadyImpl() {
412     BEGIN_OP(0);
413     return ndk::ScopedAStatus::ok();
414 }
415 
getSensorLocationConfig(SensorLocation & out)416 bool FakeFingerprintEngine::getSensorLocationConfig(SensorLocation& out) {
417     auto loc = FingerprintHalProperties::sensor_location().value_or("");
418     auto isValidStr = false;
419     auto dim = Util::split(loc, ":");
420 
421     if (dim.size() < 3 or dim.size() > 4) {
422         if (!loc.empty()) LOG(WARNING) << "Invalid sensor location input (x:y:radius):" + loc;
423         return false;
424     } else {
425         int32_t x, y, r;
426         std::string d = "";
427         if (dim.size() >= 3) {
428             isValidStr = ParseInt(dim[0], &x) && ParseInt(dim[1], &y) && ParseInt(dim[2], &r);
429         }
430         if (dim.size() >= 4) {
431             d = dim[3];
432         }
433         if (isValidStr)
434             out = {.sensorLocationX = x, .sensorLocationY = y, .sensorRadius = r, .display = d};
435 
436         return isValidStr;
437     }
438 }
getSensorLocation()439 SensorLocation FakeFingerprintEngine::getSensorLocation() {
440     SensorLocation location;
441 
442     if (getSensorLocationConfig(location)) {
443         return location;
444     } else {
445         return defaultSensorLocation();
446     }
447 }
448 
defaultSensorLocation()449 SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
450     return SensorLocation();
451 }
452 
parseIntSequence(const std::string & str,const std::string & sep)453 std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
454                                                              const std::string& sep) {
455     std::vector<std::string> seqs = Util::split(str, sep);
456     std::vector<int32_t> res;
457 
458     for (const auto& seq : seqs) {
459         int32_t val;
460         if (ParseInt(seq, &val)) {
461             res.push_back(val);
462         } else {
463             LOG(WARNING) << "Invalid int sequence:" + str;
464             res.clear();
465             break;
466         }
467     }
468 
469     return res;
470 }
471 
parseEnrollmentCaptureSingle(const std::string & str,std::vector<std::vector<int32_t>> & res)472 bool FakeFingerprintEngine::parseEnrollmentCaptureSingle(const std::string& str,
473                                                          std::vector<std::vector<int32_t>>& res) {
474     std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
475     bool aborted = true;
476 
477     do {
478         std::smatch sms;
479         // Parses strings like "1000-[5,1]" or "500"
480         std::regex ex("((\\d+)(-\\[([\\d|,]+)\\])?)");
481         if (!regex_match(str.cbegin(), str.cend(), sms, ex)) break;
482         int32_t duration;
483         if (!ParseInt(sms.str(2), &duration)) break;
484         res.push_back({duration});
485         if (!sms.str(4).empty()) {
486             auto acqv = parseIntSequence(sms.str(4));
487             if (acqv.empty()) break;
488             res.push_back(acqv);
489         } else
490             res.push_back(defaultAcquiredInfo);
491         aborted = false;
492     } while (0);
493 
494     return !aborted;
495 }
496 
parseEnrollmentCapture(const std::string & str)497 std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
498         const std::string& str) {
499     std::vector<std::vector<int32_t>> res;
500 
501     std::string s(str);
502     s.erase(std::remove_if(s.begin(), s.end(), ::isspace), s.end());
503     bool aborted = false;
504     std::smatch sms;
505     // Parses strings like "1000-[5,1],500,800-[6,5,1]"
506     //                      ---------- --- -----------
507     //  into parts:             A       B       C
508     while (regex_search(s, sms, std::regex("^(,)?(\\d+(-\\[[\\d|,]+\\])?)"))) {
509         if (!parseEnrollmentCaptureSingle(sms.str(2), res)) {
510             aborted = true;
511             break;
512         }
513         s = sms.suffix();
514     }
515     if (aborted || s.length() != 0) {
516         res.clear();
517         LOG(ERROR) << "Failed to parse enrollment captures:" + str;
518     }
519 
520     return res;
521 }
522 
convertAcquiredInfo(int32_t code)523 std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
524     std::pair<AcquiredInfo, int32_t> res;
525     if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
526         res.first = AcquiredInfo::VENDOR;
527         res.second = code - FINGERPRINT_ACQUIRED_VENDOR_BASE;
528     } else {
529         res.first = (AcquiredInfo)code;
530         res.second = 0;
531     }
532     return res;
533 }
534 
convertError(int32_t code)535 std::pair<Error, int32_t> FakeFingerprintEngine::convertError(int32_t code) {
536     std::pair<Error, int32_t> res;
537     if (code > FINGERPRINT_ERROR_VENDOR_BASE) {
538         res.first = Error::VENDOR;
539         res.second = code - FINGERPRINT_ERROR_VENDOR_BASE;
540     } else {
541         res.first = (Error)code;
542         res.second = 0;
543     }
544     return res;
545 }
546 
getLatency(const std::vector<std::optional<std::int32_t>> & latencyIn)547 int32_t FakeFingerprintEngine::getLatency(
548         const std::vector<std::optional<std::int32_t>>& latencyIn) {
549     int32_t res = DEFAULT_LATENCY;
550 
551     std::vector<int32_t> latency;
552     for (auto x : latencyIn)
553         if (x.has_value()) latency.push_back(*x);
554 
555     switch (latency.size()) {
556         case 0:
557             break;
558         case 1:
559             res = latency[0];
560             break;
561         case 2:
562             res = getRandomInRange(latency[0], latency[1]);
563             break;
564         default:
565             LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
566             break;
567     }
568 
569     return res;
570 }
571 
getRandomInRange(int32_t bound1,int32_t bound2)572 int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
573     std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
574     return dist(mRandom);
575 }
576 
checkSensorLockout(ISessionCallback * cb)577 bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) {
578     FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
579     if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
580         LOG(ERROR) << "Fail: lockout permanent";
581         cb->onLockoutPermanent();
582         isLockoutTimerAborted = true;
583         return true;
584     } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
585         int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
586         LOG(ERROR) << "Fail: lockout timed " << timeLeft;
587         cb->onLockoutTimed(timeLeft);
588         if (isLockoutTimerSupported && !isLockoutTimerStarted) startLockoutTimer(timeLeft, cb);
589         return true;
590     }
591     return false;
592 }
593 
startLockoutTimer(int64_t timeout,ISessionCallback * cb)594 void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
595     BEGIN_OP(0);
596     std::function<void(ISessionCallback*)> action =
597             std::bind(&FakeFingerprintEngine::lockoutTimerExpired, this, std::placeholders::_1);
598     std::thread([timeout, action, cb]() {
599         std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
600         action(cb);
601     }).detach();
602 
603     isLockoutTimerStarted = true;
604 }
lockoutTimerExpired(ISessionCallback * cb)605 void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
606     if (!isLockoutTimerAborted) {
607         clearLockout(cb);
608     }
609     isLockoutTimerStarted = false;
610     isLockoutTimerAborted = false;
611 }
612 }  // namespace aidl::android::hardware::biometrics::fingerprint
613