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