blob: d0250af3bf845f426654c8bc0d6d4977695de498 [file] [log] [blame]
Joe Bolingerde94aa02021-12-09 17:00:32 -08001/*
2 * Copyright (C) 2021 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
Joe Bolingerde94aa02021-12-09 17:00:32 -080019#include <android-base/logging.h>
Joshua McCloskeyc8c0bad2022-05-10 05:17:44 +000020
21#include <fingerprint.sysprop.h>
Joe Bolingerde94aa02021-12-09 17:00:32 -080022#include <chrono>
23#include <regex>
24#include <thread>
25
Joshua McCloskeyc8c0bad2022-05-10 05:17:44 +000026#include "util/CancellationSignal.h"
27
Joe Bolingerde94aa02021-12-09 17:00:32 -080028#define SLEEP_MS(x) \
29 if (x > 0) std::this_thread::sleep_for(std::chrono::milliseconds(x))
30#define BEGIN_OP(x) \
31 do { \
32 LOG(INFO) << __func__; \
33 SLEEP_MS(x); \
34 } while (0)
35#define IS_TRUE(x) ((x == "1") || (x == "true"))
36
37// This is for non-test situations, such as casual cuttlefish users, that don't
38// set an explicit value.
39// Some operations (i.e. enroll, authenticate) will be executed in tight loops
40// by parts of the UI or fail if there is no latency. For example, the
41// fingerprint settings page constantly runs auth and the enrollment UI uses a
42// cancel/restart cycle that requires some latency while the activities change.
43#define DEFAULT_LATENCY 2000
44
45using namespace ::android::fingerprint::virt;
46using namespace ::aidl::android::hardware::biometrics::fingerprint;
47
48int64_t getSystemNanoTime() {
49 timespec now;
50 clock_gettime(CLOCK_MONOTONIC, &now);
51 return now.tv_sec * 1000000000LL + now.tv_nsec;
52}
53
54bool hasElapsed(int64_t start, int64_t durationMillis) {
55 auto now = getSystemNanoTime();
56 if (now < start) return true;
57 if (durationMillis <= 0) return true;
58 return ((now - start) / 1000000LL) > durationMillis;
59}
60
61std::vector<std::string> split(const std::string& str, const std::string& sep) {
62 std::regex regex(sep);
63 std::vector<std::string> parts(std::sregex_token_iterator(str.begin(), str.end(), regex, -1),
64 std::sregex_token_iterator());
65 return parts;
66}
67
68namespace aidl::android::hardware::biometrics::fingerprint {
69
70void FakeFingerprintEngine::generateChallengeImpl(ISessionCallback* cb) {
71 BEGIN_OP(0);
72 std::uniform_int_distribution<int64_t> dist;
73 auto challenge = dist(mRandom);
74 FingerprintHalProperties::challenge(challenge);
75 cb->onChallengeGenerated(challenge);
76}
77
78void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
79 BEGIN_OP(0);
80 FingerprintHalProperties::challenge({});
81 cb->onChallengeRevoked(challenge);
82}
83
84void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
85 const keymaster::HardwareAuthToken& hat,
86 const std::future<void>& cancel) {
87 BEGIN_OP(FingerprintHalProperties::operation_enroll_latency().value_or(DEFAULT_LATENCY));
88
89 // Do proper HAT verification in the real implementation.
90 if (hat.mac.empty()) {
91 LOG(ERROR) << "Fail: hat";
92 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
93 return;
94 }
95
96 if (FingerprintHalProperties::operation_enroll_fails().value_or(false)) {
97 LOG(ERROR) << "Fail: operation_enroll_fails";
98 cb->onError(Error::VENDOR, 0 /* vendorError */);
99 return;
100 }
101
102 // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
103 auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
104 auto parts = split(nextEnroll, ":");
105 if (parts.size() != 3) {
106 LOG(ERROR) << "Fail: invalid next_enrollment";
107 cb->onError(Error::VENDOR, 0 /* vendorError */);
108 return;
109 }
110 auto enrollmentId = std::stoi(parts[0]);
111 auto progress = split(parts[1], ",");
112 for (size_t i = 0; i < progress.size(); i++) {
113 auto left = progress.size() - i - 1;
114 SLEEP_MS(std::stoi(progress[i]));
115
116 if (shouldCancel(cancel)) {
117 LOG(ERROR) << "Fail: cancel";
118 cb->onError(Error::CANCELED, 0 /* vendorCode */);
119 return;
120 }
121
122 cb->onAcquired(AcquiredInfo::GOOD, 0 /* vendorCode */);
123 if (left == 0 && !IS_TRUE(parts[2])) { // end and failed
124 LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
125 FingerprintHalProperties::next_enrollment({});
126 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
127 } else { // progress and update props if last time
128 if (left == 0) {
129 auto enrollments = FingerprintHalProperties::enrollments();
130 enrollments.emplace_back(enrollmentId);
131 FingerprintHalProperties::enrollments(enrollments);
132 FingerprintHalProperties::next_enrollment({});
133 LOG(INFO) << "Enrolled: " << enrollmentId;
134 }
135 cb->onEnrollmentProgress(enrollmentId, left);
136 }
137 }
138}
139
140void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* operationId */,
141 const std::future<void>& cancel) {
142 BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));
143
144 auto now = getSystemNanoTime();
145 int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
146 do {
147 if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
148 LOG(ERROR) << "Fail: operation_authenticate_fails";
149 cb->onError(Error::VENDOR, 0 /* vendorError */);
150 return;
151 }
152
153 if (FingerprintHalProperties::lockout().value_or(false)) {
154 LOG(ERROR) << "Fail: lockout";
155 cb->onLockoutPermanent();
156 cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
157 return;
158 }
159
160 if (shouldCancel(cancel)) {
161 LOG(ERROR) << "Fail: cancel";
162 cb->onError(Error::CANCELED, 0 /* vendorCode */);
163 return;
164 }
165
166 auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
167 auto enrolls = FingerprintHalProperties::enrollments();
168 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
169 if (id > 0 && isEnrolled) {
170 cb->onAuthenticationSucceeded(id, {} /* hat */);
171 return;
172 }
173
174 SLEEP_MS(100);
175 } while (!hasElapsed(now, duration));
176
177 LOG(ERROR) << "Fail: not enrolled";
178 cb->onAuthenticationFailed();
179 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
180}
181
182void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
183 const std::future<void>& cancel) {
184 BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
185 DEFAULT_LATENCY));
186
187 if (FingerprintHalProperties::operation_detect_interaction_fails().value_or(false)) {
188 LOG(ERROR) << "Fail: operation_detect_interaction_fails";
189 cb->onError(Error::VENDOR, 0 /* vendorError */);
190 return;
191 }
192
193 if (shouldCancel(cancel)) {
194 LOG(ERROR) << "Fail: cancel";
195 cb->onError(Error::CANCELED, 0 /* vendorCode */);
196 return;
197 }
198
199 auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
200 auto enrolls = FingerprintHalProperties::enrollments();
201 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
202 if (id <= 0 || !isEnrolled) {
203 LOG(ERROR) << "Fail: not enrolled";
204 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
205 return;
206 }
207
208 cb->onInteractionDetected();
209}
210
211void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
212 BEGIN_OP(0);
213
214 std::vector<int32_t> ids;
215 for (auto& enrollment : FingerprintHalProperties::enrollments()) {
216 auto id = enrollment.value_or(0);
217 if (id > 0) {
218 ids.push_back(id);
219 }
220 }
221
222 cb->onEnrollmentsEnumerated(ids);
223}
224
225void FakeFingerprintEngine::removeEnrollmentsImpl(ISessionCallback* cb,
226 const std::vector<int32_t>& enrollmentIds) {
227 BEGIN_OP(0);
228
229 std::vector<std::optional<int32_t>> newEnrollments;
230 std::vector<int32_t> removed;
231 for (auto& enrollment : FingerprintHalProperties::enrollments()) {
232 auto id = enrollment.value_or(0);
233 if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) != enrollmentIds.end()) {
234 removed.push_back(id);
235 } else if (id > 0) {
236 newEnrollments.emplace_back(id);
237 }
238 }
239 FingerprintHalProperties::enrollments(newEnrollments);
240
241 cb->onEnrollmentsRemoved(enrollmentIds);
242}
243
244void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
245 BEGIN_OP(0);
246 cb->onAuthenticatorIdRetrieved(FingerprintHalProperties::authenticator_id().value_or(0));
247}
248
249void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
250 BEGIN_OP(0);
251 auto id = FingerprintHalProperties::authenticator_id().value_or(0);
252 auto newId = id + 1;
253 FingerprintHalProperties::authenticator_id(newId);
254 cb->onAuthenticatorIdInvalidated(newId);
255}
256
257void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
258 const keymaster::HardwareAuthToken& /*hat*/) {
259 BEGIN_OP(0);
260 FingerprintHalProperties::lockout(false);
261 cb->onLockoutCleared();
262}
263
264} // namespace aidl::android::hardware::biometrics::fingerprint