• 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),
36       mWorkMode(WorkMode::kIdle),
37       isLockoutTimerSupported(true) {}
38 
generateChallengeImpl(ISessionCallback * cb)39 void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
40     BEGIN_OP(0);
41     std::uniform_int_distribution<int64_t> dist;
42     auto challenge = dist(mRandom);
43     Fingerprint::cfg().set<std::int64_t>("challenge", challenge);
44     cb->onChallengeGenerated(challenge);
45 }
46 
revokeChallengeImpl(ISessionCallback * cb,int64_t challenge)47 void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
48     BEGIN_OP(0);
49     Fingerprint::cfg().setopt<OptInt64>("challenge", std::nullopt);
50     cb->onChallengeRevoked(challenge);
51 }
52 
enrollImpl(ISessionCallback * cb,const keymaster::HardwareAuthToken & hat,const std::future<void> & cancel)53 void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
54                                        const keymaster::HardwareAuthToken& hat,
55                                        const std::future<void>& cancel) {
56     BEGIN_OP(0);
57 
58     // Do proper HAT verification in the real implementation.
59     if (hat.mac.empty()) {
60         LOG(ERROR) << "Fail: hat";
61         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
62         return;
63     }
64 
65     waitForFingerDown(cb, cancel);
66 
67     updateContext(WorkMode::kEnroll, cb, const_cast<std::future<void>&>(cancel), 0, hat);
68 }
69 
authenticateImpl(ISessionCallback * cb,int64_t operationId,const std::future<void> & cancel)70 void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t operationId,
71                                              const std::future<void>& cancel) {
72     BEGIN_OP(0);
73 
74     waitForFingerDown(cb, cancel);
75 
76     updateContext(WorkMode::kAuthenticate, cb, const_cast<std::future<void>&>(cancel), operationId,
77                   keymaster::HardwareAuthToken());
78 }
79 
detectInteractionImpl(ISessionCallback * cb,const std::future<void> & cancel)80 void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
81                                                   const std::future<void>& cancel) {
82     BEGIN_OP(0);
83 
84     auto detectInteractionSupported = Fingerprint::cfg().get<bool>("detect_interaction");
85     if (!detectInteractionSupported) {
86         LOG(ERROR) << "Detect interaction is not supported";
87         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
88         return;
89     }
90 
91     waitForFingerDown(cb, cancel);
92 
93     updateContext(WorkMode::kDetectInteract, cb, const_cast<std::future<void>&>(cancel), 0,
94                   keymaster::HardwareAuthToken());
95 }
96 
updateContext(WorkMode mode,ISessionCallback * cb,std::future<void> & cancel,int64_t operationId,const keymaster::HardwareAuthToken & hat)97 void FakeFingerprintEngine::updateContext(WorkMode mode, ISessionCallback* cb,
98                                           std::future<void>& cancel, int64_t operationId,
99                                           const keymaster::HardwareAuthToken& hat) {
100     mCancel = std::move(cancel);
101     mWorkMode = mode;
102     mCb = cb;
103     mOperationId = operationId;
104     mHat = hat;
105 }
106 
fingerDownAction()107 void FakeFingerprintEngine::fingerDownAction() {
108     bool isTerminal = false;
109     LOG(INFO) << __func__;
110     switch (mWorkMode) {
111         case WorkMode::kAuthenticate:
112             isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel);
113             break;
114         case WorkMode::kEnroll:
115             isTerminal = onEnrollFingerDown(mCb, mHat, mCancel);
116             break;
117         case WorkMode::kDetectInteract:
118             isTerminal = onDetectInteractFingerDown(mCb, mCancel);
119             break;
120         default:
121             LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode;
122             break;
123     }
124 
125     if (isTerminal) {
126         mWorkMode = WorkMode::kIdle;
127     }
128 }
129 
onEnrollFingerDown(ISessionCallback * cb,const keymaster::HardwareAuthToken &,const std::future<void> & cancel)130 bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
131                                                const keymaster::HardwareAuthToken&,
132                                                const std::future<void>& cancel) {
133     BEGIN_OP(getLatency(Fingerprint::cfg().getopt<OptIntVec>("operation_enroll_latency")));
134 
135     // Force error-out
136     auto err = Fingerprint::cfg().get<std::int32_t>("operation_enroll_error");
137     if (err != 0) {
138         LOG(ERROR) << "Fail: operation_enroll_error";
139         auto ec = convertError(err);
140         cb->onError(ec.first, ec.second);
141         return true;
142     }
143 
144     // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
145     auto nextEnroll = Fingerprint::cfg().get<std::string>("next_enrollment");
146     auto parts = Util::split(nextEnroll, ":");
147     if (parts.size() != 3) {
148         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
149         cb->onError(Error::VENDOR, 0 /* vendorError */);
150         return true;
151     }
152     auto enrollmentId = std::stoi(parts[0]);
153     auto progress = Util::parseEnrollmentCapture(parts[1]);
154     for (size_t i = 0; i < progress.size(); i += 2) {
155         auto left = (progress.size() - i) / 2 - 1;
156         auto duration = progress[i][0];
157         auto acquired = progress[i + 1];
158         auto N = acquired.size();
159 
160         for (int j = 0; j < N; j++) {
161             SLEEP_MS(duration / N);
162 
163             if (shouldCancel(cancel)) {
164                 LOG(ERROR) << "Fail: cancel";
165                 cb->onError(Error::CANCELED, 0 /* vendorCode */);
166                 return true;
167             }
168             auto ac = convertAcquiredInfo(acquired[j]);
169             cb->onAcquired(ac.first, ac.second);
170         }
171 
172         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
173             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
174             Fingerprint::cfg().set<std::string>("next_enrollment", "");
175             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
176         } else {  // progress and update props if last time
177             LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
178             if (left == 0) {
179                 auto enrollments = Fingerprint::cfg().getopt<OptIntVec>("enrollments");
180                 enrollments.emplace_back(enrollmentId);
181                 Fingerprint::cfg().setopt<OptIntVec>("enrollments", enrollments);
182                 Fingerprint::cfg().setopt<OptString>("next_enrollment", std::nullopt);
183                 // change authenticatorId after new enrollment
184                 auto id = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
185                 auto newId = id + 1;
186                 Fingerprint::cfg().set<std::int64_t>("authenticator_id", newId);
187                 LOG(INFO) << "Enrolled: " << enrollmentId;
188             }
189             cb->onEnrollmentProgress(enrollmentId, left);
190         }
191     }
192 
193     return true;
194 }
195 
onAuthenticateFingerDown(ISessionCallback * cb,int64_t,const std::future<void> & cancel)196 bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
197                                                      int64_t /* operationId */,
198                                                      const std::future<void>& cancel) {
199     BEGIN_OP(getLatency(Fingerprint::cfg().getopt<OptIntVec>("operation_authenticate_latency")));
200 
201     int64_t now = Util::getSystemNanoTime();
202     int64_t duration = Fingerprint::cfg().get<std::int32_t>("operation_authenticate_duration");
203     auto acquired = Fingerprint::cfg().get<std::string>("operation_authenticate_acquired");
204     auto acquiredInfos = Util::parseIntSequence(acquired);
205     int N = acquiredInfos.size();
206 
207     if (N == 0) {
208         LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
209         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
210         return true;
211     }
212 
213     // got lockout?
214     if (checkSensorLockout(cb)) {
215         return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode();
216     }
217 
218     int i = 0;
219     do {
220         if (Fingerprint::cfg().get<bool>("operation_authenticate_fails")) {
221             LOG(ERROR) << "Fail: operation_authenticate_fails";
222             mLockoutTracker.addFailedAttempt();
223             cb->onAuthenticationFailed();
224             return false;
225         }
226 
227         auto err = Fingerprint::cfg().get<std::int32_t>("operation_authenticate_error");
228         if (err != 0) {
229             LOG(ERROR) << "Fail: operation_authenticate_error";
230             auto ec = convertError(err);
231             cb->onError(ec.first, ec.second);
232             return true; /* simply terminating current operation for any user inserted error,
233                             revisit if tests need*/
234         }
235 
236         if (Fingerprint::cfg().get<bool>("lockout")) {
237             LOG(ERROR) << "Fail: lockout";
238             cb->onLockoutPermanent();
239             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
240             return true;
241         }
242 
243         if (shouldCancel(cancel)) {
244             LOG(ERROR) << "Fail: cancel";
245             cb->onError(Error::CANCELED, 0 /* vendorCode */);
246             return true;
247         }
248 
249         if (i < N) {
250             auto ac = convertAcquiredInfo(acquiredInfos[i]);
251             cb->onAcquired(ac.first, ac.second);
252             i++;
253         }
254 
255         SLEEP_MS(duration / N);
256     } while (!Util::hasElapsed(now, duration));
257 
258     auto id = Fingerprint::cfg().get<std::int32_t>("enrollment_hit");
259     auto enrolls = Fingerprint::cfg().getopt<OptIntVec>("enrollments");
260     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
261     if (id > 0 && isEnrolled) {
262         cb->onAuthenticationSucceeded(id, {} /* hat */);
263         mLockoutTracker.reset();
264         return true;
265     } else {
266         LOG(ERROR) << "Fail: fingerprint not enrolled";
267         cb->onAuthenticationFailed();
268         mLockoutTracker.addFailedAttempt();
269         checkSensorLockout(cb);
270         return false;
271     }
272 }
273 
onDetectInteractFingerDown(ISessionCallback * cb,const std::future<void> & cancel)274 bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
275                                                        const std::future<void>& cancel) {
276     BEGIN_OP(getLatency(
277             Fingerprint::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
278 
279     int32_t duration =
280             Fingerprint::cfg().get<std::int32_t>("operation_detect_interaction_duration");
281 
282     auto acquired = Fingerprint::cfg().get<std::string>("operation_detect_interaction_acquired");
283     auto acquiredInfos = Util::parseIntSequence(acquired);
284     int N = acquiredInfos.size();
285     int64_t now = Util::getSystemNanoTime();
286 
287     if (N == 0) {
288         LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
289         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
290         return true;
291     }
292 
293     int i = 0;
294     do {
295         auto err = Fingerprint::cfg().get<std::int32_t>("operation_detect_interaction_error");
296         if (err != 0) {
297             LOG(ERROR) << "Fail: operation_detect_interaction_error";
298             auto ec = convertError(err);
299             cb->onError(ec.first, ec.second);
300             return true;
301         }
302 
303         if (shouldCancel(cancel)) {
304             LOG(ERROR) << "Fail: cancel";
305             cb->onError(Error::CANCELED, 0 /* vendorCode */);
306             return true;
307         }
308 
309         if (i < N) {
310             auto ac = convertAcquiredInfo(acquiredInfos[i]);
311             cb->onAcquired(ac.first, ac.second);
312             i++;
313         }
314         SLEEP_MS(duration / N);
315     } while (!Util::hasElapsed(now, duration));
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 : Fingerprint::cfg().getopt<OptIntVec>("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 : Fingerprint::cfg().getopt<OptIntVec>("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     Fingerprint::cfg().setopt<OptIntVec>("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 (Fingerprint::cfg().getopt<OptIntVec>("enrollments").size() == 0) {
359         authenticatorId = 0;
360     } else {
361         authenticatorId = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
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 (Fingerprint::cfg().getopt<OptIntVec>("enrollments").size() == 0) {
371         newId = 0;
372     } else {
373         auto id = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
374         newId = id + 1;
375     }
376     Fingerprint::cfg().set<std::int64_t>("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     if (isLockoutTimerStarted) isLockoutTimerAborted = true;
390 }
391 
clearLockout(ISessionCallback * cb)392 void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
393     Fingerprint::cfg().set<bool>("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     mFingerIsDown = false;
409     return ndk::ScopedAStatus::ok();
410 }
411 
onUiReadyImpl()412 ndk::ScopedAStatus FakeFingerprintEngine::onUiReadyImpl() {
413     BEGIN_OP(0);
414     return ndk::ScopedAStatus::ok();
415 }
416 
getSensorLocationConfig(SensorLocation & out)417 bool FakeFingerprintEngine::getSensorLocationConfig(SensorLocation& out) {
418     auto loc = Fingerprint::cfg().get<std::string>("sensor_location");
419     auto isValidStr = false;
420     auto dim = Util::split(loc, ":");
421 
422     if (dim.size() < 3 or dim.size() > 4) {
423         if (!loc.empty()) LOG(WARNING) << "Invalid sensor location input (x:y:radius):" + loc;
424         return false;
425     } else {
426         int32_t x, y, r;
427         std::string d = "";
428         if (dim.size() >= 3) {
429             isValidStr = ParseInt(dim[0], &x) && ParseInt(dim[1], &y) && ParseInt(dim[2], &r);
430         }
431         if (dim.size() >= 4) {
432             d = dim[3];
433         }
434         if (isValidStr)
435             out = {.sensorLocationX = x, .sensorLocationY = y, .sensorRadius = r, .display = d};
436 
437         return isValidStr;
438     }
439 }
getSensorLocation()440 SensorLocation FakeFingerprintEngine::getSensorLocation() {
441     SensorLocation location;
442 
443     if (getSensorLocationConfig(location)) {
444         return location;
445     } else {
446         return defaultSensorLocation();
447     }
448 }
449 
defaultSensorLocation()450 SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
451     return SensorLocation();
452 }
453 
convertAcquiredInfo(int32_t code)454 std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
455     std::pair<AcquiredInfo, int32_t> res;
456     if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
457         res.first = AcquiredInfo::VENDOR;
458         res.second = code - FINGERPRINT_ACQUIRED_VENDOR_BASE;
459     } else {
460         res.first = (AcquiredInfo)code;
461         res.second = 0;
462     }
463     return res;
464 }
465 
convertError(int32_t code)466 std::pair<Error, int32_t> FakeFingerprintEngine::convertError(int32_t code) {
467     std::pair<Error, int32_t> res;
468     if (code > FINGERPRINT_ERROR_VENDOR_BASE) {
469         res.first = Error::VENDOR;
470         res.second = code - FINGERPRINT_ERROR_VENDOR_BASE;
471     } else {
472         res.first = (Error)code;
473         res.second = 0;
474     }
475     return res;
476 }
477 
getLatency(const std::vector<std::optional<std::int32_t>> & latencyIn)478 int32_t FakeFingerprintEngine::getLatency(
479         const std::vector<std::optional<std::int32_t>>& latencyIn) {
480     int32_t res = DEFAULT_LATENCY;
481 
482     std::vector<int32_t> latency;
483     for (auto x : latencyIn)
484         if (x.has_value()) latency.push_back(*x);
485 
486     switch (latency.size()) {
487         case 0:
488             break;
489         case 1:
490             res = latency[0];
491             break;
492         case 2:
493             res = getRandomInRange(latency[0], latency[1]);
494             break;
495         default:
496             LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
497             break;
498     }
499 
500     return res;
501 }
502 
getRandomInRange(int32_t bound1,int32_t bound2)503 int32_t FakeFingerprintEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
504     std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
505     return dist(mRandom);
506 }
507 
checkSensorLockout(ISessionCallback * cb)508 bool FakeFingerprintEngine::checkSensorLockout(ISessionCallback* cb) {
509     FakeLockoutTracker::LockoutMode lockoutMode = mLockoutTracker.getMode();
510     if (lockoutMode == FakeLockoutTracker::LockoutMode::kPermanent) {
511         LOG(ERROR) << "Fail: lockout permanent";
512         cb->onLockoutPermanent();
513         isLockoutTimerAborted = true;
514         return true;
515     } else if (lockoutMode == FakeLockoutTracker::LockoutMode::kTimed) {
516         int64_t timeLeft = mLockoutTracker.getLockoutTimeLeft();
517         LOG(ERROR) << "Fail: lockout timed " << timeLeft;
518         cb->onLockoutTimed(timeLeft);
519         if (isLockoutTimerSupported && !isLockoutTimerStarted) startLockoutTimer(timeLeft, cb);
520         return true;
521     }
522     return false;
523 }
524 
startLockoutTimer(int64_t timeout,ISessionCallback * cb)525 void FakeFingerprintEngine::startLockoutTimer(int64_t timeout, ISessionCallback* cb) {
526     BEGIN_OP(0);
527     std::function<void(ISessionCallback*)> action =
528             std::bind(&FakeFingerprintEngine::lockoutTimerExpired, this, std::placeholders::_1);
529     std::thread([timeout, action, cb]() {
530         std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
531         action(cb);
532     }).detach();
533 
534     isLockoutTimerStarted = true;
535 }
lockoutTimerExpired(ISessionCallback * cb)536 void FakeFingerprintEngine::lockoutTimerExpired(ISessionCallback* cb) {
537     BEGIN_OP(0);
538     if (!isLockoutTimerAborted) {
539         clearLockout(cb);
540     }
541     isLockoutTimerStarted = false;
542     isLockoutTimerAborted = false;
543 }
544 
waitForFingerDown(ISessionCallback * cb,const std::future<void> & cancel)545 void FakeFingerprintEngine::waitForFingerDown(ISessionCallback* cb,
546                                               const std::future<void>& cancel) {
547     if (mFingerIsDown) {
548         LOG(WARNING) << "waitForFingerDown: mFingerIsDown==true already!";
549     }
550 
551     while (!mFingerIsDown) {
552         if (shouldCancel(cancel)) {
553             LOG(ERROR) << "waitForFingerDown, Fail: cancel";
554             cb->onError(Error::CANCELED, 0 /* vendorCode */);
555             return;
556         }
557         SLEEP_MS(10);
558     }
559 }
560 
561 }  // namespace aidl::android::hardware::biometrics::fingerprint
562