blob: 578231d1ca3da7f8f99482ea235cf0bac920743f [file] [log] [blame]
Joshua McCloskeydb009a52022-05-10 05:18:20 +00001#include "FakeFaceEngine.h"
2
3#include <android-base/logging.h>
4
5#include <face.sysprop.h>
6
7#include "util/CancellationSignal.h"
8#include "util/Util.h"
9
10using namespace ::android::face::virt;
11
12namespace aidl::android::hardware::biometrics::face {
13
14FaceSensorType FakeFaceEngine::GetSensorType() {
15 std::string type = FaceHalProperties::type().value_or("");
16 if (type == "IR") {
17 return FaceSensorType::IR;
18 } else {
19 FaceHalProperties::type("RGB");
20 return FaceSensorType::RGB;
21 }
22}
23
24common::SensorStrength FakeFaceEngine::GetSensorStrength() {
25 std::string strength = FaceHalProperties::strength().value_or("");
26 if (strength == "convenience") {
27 return common::SensorStrength::CONVENIENCE;
28 } else if (strength == "weak") {
29 return common::SensorStrength::WEAK;
30 } else {
31 FaceHalProperties::strength("strong");
32 return common::SensorStrength::STRONG;
33 }
34}
35
36void FakeFaceEngine::generateChallengeImpl(ISessionCallback* cb) {
37 BEGIN_OP(0);
38 std::uniform_int_distribution<int64_t> dist;
39 auto challenge = dist(mRandom);
40 FaceHalProperties::challenge(challenge);
41 cb->onChallengeGenerated(challenge);
42}
43
44void FakeFaceEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
45 BEGIN_OP(0);
46 FaceHalProperties::challenge({});
47 cb->onChallengeRevoked(challenge);
48}
49void FakeFaceEngine::getEnrollmentConfigImpl(ISessionCallback* /*cb*/,
50 std::vector<EnrollmentStageConfig>* /*return_val*/) {}
51void FakeFaceEngine::enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
52 EnrollmentType /*enrollmentType*/,
53 const std::vector<Feature>& /*features*/,
54 const std::future<void>& cancel) {
55 BEGIN_OP(FaceHalProperties::operation_start_enroll_latency().value_or(0));
56 // format is "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>:<delay>:<succeeds>...
57 auto nextEnroll = FaceHalProperties::next_enrollment().value_or("");
58 // Erase the next enrollment
59 FaceHalProperties::next_enrollment({});
60
61 AuthenticationFrame frame;
62 frame.data.acquiredInfo = AcquiredInfo::START;
63 frame.data.vendorCode = 0;
64 cb->onAuthenticationFrame(frame);
65
66 // Do proper HAT verification in the real implementation.
67 if (hat.mac.empty()) {
68 LOG(ERROR) << "Fail: hat";
69 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
70 return;
71 }
72
73 if (FaceHalProperties::operation_enroll_fails().value_or(false)) {
74 LOG(ERROR) << "Fail: operation_enroll_fails";
75 cb->onError(Error::VENDOR, 0 /* vendorError */);
76 return;
77 }
78
79 auto parts = Util::split(nextEnroll, ",");
80 if (parts.size() < 2) {
81 LOG(ERROR) << "Fail: invalid next_enrollment for : " << nextEnroll;
82 cb->onError(Error::VENDOR, 0 /* vendorError */);
83 return;
84 }
85
86 auto enrollmentId = std::stoi(parts[0]);
87 const int numBuckets = parts.size() - 1;
88 for (size_t i = 1; i < parts.size(); i++) {
89 auto enrollHit = Util::split(parts[i], ":");
90 if (enrollHit.size() != 3) {
91 LOG(ERROR) << "Error when unpacking enrollment hit: " << parts[i];
92 cb->onError(Error::VENDOR, 0 /* vendorError */);
93 }
94 std::string bucket = enrollHit[0];
95 std::string delay = enrollHit[1];
96 std::string succeeds = enrollHit[2];
97
98 SLEEP_MS(std::stoi(delay));
99
100 if (shouldCancel(cancel)) {
101 LOG(ERROR) << "Fail: cancel";
102 cb->onError(Error::CANCELED, 0 /* vendorCode */);
103 return;
104 }
105
106 if (!IS_TRUE(succeeds)) { // end and failed
107 LOG(ERROR) << "Fail: requested by caller: " << parts[i];
108 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
109 return;
110 }
111
112 EnrollmentFrame frame;
113
114 frame.data.acquiredInfo = AcquiredInfo::GOOD;
115 frame.data.vendorCode = 0;
116 cb->onEnrollmentFrame(frame);
117
118 frame.data.acquiredInfo = AcquiredInfo::VENDOR;
119 frame.data.vendorCode = std::stoi(bucket);
120 cb->onEnrollmentFrame(frame);
121
122 int remainingBuckets = numBuckets - i;
123 if (remainingBuckets > 0) {
124 cb->onEnrollmentProgress(enrollmentId, remainingBuckets);
125 }
126 }
127
128 auto enrollments = FaceHalProperties::enrollments();
129 enrollments.push_back(enrollmentId);
130 FaceHalProperties::enrollments(enrollments);
131 LOG(INFO) << "enrolled : " << enrollmentId;
132 cb->onEnrollmentProgress(enrollmentId, 0);
133}
134
135void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
136 const std::future<void>& cancel) {
137 BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
138
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000139 auto id = FaceHalProperties::enrollment_hit().value_or(0);
140 auto enrolls = FaceHalProperties::enrollments();
141 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
Jeff Pu484d2e72023-09-25 15:11:19 +0000142
143 auto vec2str = [](std::vector<AcquiredInfo> va) {
144 std::stringstream ss;
145 bool isFirst = true;
146 for (auto ac : va) {
147 if (!isFirst) ss << ",";
148 ss << std::to_string((int8_t)ac);
149 isFirst = false;
150 }
151 return ss.str();
152 };
153
154 // default behavior mimic face sensor in U
155 int64_t defaultAuthDuration = 500;
156 std::string defaultAcquiredInfo =
157 vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
158 if (!isEnrolled) {
159 std::vector<AcquiredInfo> v;
160 for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
161 defaultAcquiredInfo += "," + vec2str(v);
162 defaultAuthDuration = 2100;
163 } else {
164 defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
165 AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
166 AcquiredInfo::GOOD, AcquiredInfo::GOOD});
167 }
168
169 int64_t now = Util::getSystemNanoTime();
170 int64_t duration =
171 FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
172 auto acquired =
173 FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
174 auto acquiredInfos = Util::parseIntSequence(acquired);
175 int N = acquiredInfos.size();
176
177 if (N == 0) {
178 LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000179 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
180 return;
181 }
182
Jeff Pu484d2e72023-09-25 15:11:19 +0000183 int i = 0;
184 do {
185 if (FaceHalProperties::lockout().value_or(false)) {
186 LOG(ERROR) << "Fail: lockout";
187 cb->onLockoutPermanent();
188 cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
189 return;
190 }
191
192 if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
193 LOG(ERROR) << "Fail: operation_authenticate_fails";
194 cb->onAuthenticationFailed();
195 return;
196 }
197
198 auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
199 if (err != 0) {
200 LOG(ERROR) << "Fail: operation_authenticate_error";
201 auto ec = convertError(err);
202 cb->onError(ec.first, ec.second);
203 return; /* simply terminating current operation for any user inserted error,
204 revisit if tests need*/
205 }
206
207 if (shouldCancel(cancel)) {
208 LOG(ERROR) << "Fail: cancel";
209 cb->onError(Error::CANCELED, 0 /* vendorCode */);
210 return;
211 }
212
213 if (i < N) {
214 auto ac = convertAcquiredInfo(acquiredInfos[i]);
215 AuthenticationFrame frame;
216 frame.data.acquiredInfo = ac.first;
217 frame.data.vendorCode = ac.second;
218 cb->onAuthenticationFrame(frame);
219 LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
220 << ")";
221 i++;
222 }
223
224 SLEEP_MS(duration / N);
225 } while (!Util::hasElapsed(now, duration));
226
227 if (id > 0 && isEnrolled) {
228 cb->onAuthenticationSucceeded(id, {} /* hat */);
229 return;
230 } else {
231 LOG(ERROR) << "Fail: face not enrolled";
232 cb->onAuthenticationFailed();
233 cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
234 return;
235 }
236}
237
238std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
239 std::pair<AcquiredInfo, int32_t> res;
240 if (code > FACE_ACQUIRED_VENDOR_BASE) {
241 res.first = AcquiredInfo::VENDOR;
242 res.second = code - FACE_ACQUIRED_VENDOR_BASE;
243 } else {
244 res.first = (AcquiredInfo)code;
245 res.second = 0;
246 }
247 return res;
248}
249
250std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
251 std::pair<Error, int32_t> res;
252 if (code > FACE_ERROR_VENDOR_BASE) {
253 res.first = Error::VENDOR;
254 res.second = code - FACE_ERROR_VENDOR_BASE;
255 } else {
256 res.first = (Error)code;
257 res.second = 0;
258 }
259 return res;
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000260}
261
262void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
263 BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
264
265 if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
266 LOG(ERROR) << "Fail: operation_detect_interaction_fails";
267 cb->onError(Error::VENDOR, 0 /* vendorError */);
268 return;
269 }
270
271 if (shouldCancel(cancel)) {
272 LOG(ERROR) << "Fail: cancel";
273 cb->onError(Error::CANCELED, 0 /* vendorCode */);
274 return;
275 }
276
277 auto id = FaceHalProperties::enrollment_hit().value_or(0);
278 auto enrolls = FaceHalProperties::enrollments();
279 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
280 if (id <= 0 || !isEnrolled) {
281 LOG(ERROR) << "Fail: not enrolled";
282 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
283 return;
284 }
285
286 cb->onInteractionDetected();
287}
288
289void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
290 BEGIN_OP(0);
291 std::vector<int32_t> enrollments;
292 for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
293 if (enrollmentId) {
294 enrollments.push_back(*enrollmentId);
295 }
296 }
297 cb->onEnrollmentsEnumerated(enrollments);
298}
299
300void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
301 const std::vector<int32_t>& enrollmentIds) {
302 BEGIN_OP(0);
303
304 std::vector<std::optional<int32_t>> newEnrollments;
305 for (const auto& enrollment : FaceHalProperties::enrollments()) {
306 auto id = enrollment.value_or(0);
307 if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
308 newEnrollments.emplace_back(id);
309 }
310 }
311 FaceHalProperties::enrollments(newEnrollments);
312 cb->onEnrollmentsRemoved(enrollmentIds);
313}
314
315void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
316 BEGIN_OP(0);
317
318 if (FaceHalProperties::enrollments().empty()) {
319 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
320 return;
321 }
322
323 std::vector<Feature> featuresToReturn = {};
324 for (const auto& feature : FaceHalProperties::features()) {
325 if (feature) {
326 featuresToReturn.push_back((Feature)(*feature));
327 }
328 }
329 cb->onFeaturesRetrieved(featuresToReturn);
330}
331
332void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
333 Feature feature, bool enabled) {
334 BEGIN_OP(0);
335
336 if (FaceHalProperties::enrollments().empty()) {
337 LOG(ERROR) << "Unable to set feature, enrollments are empty";
338 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
339 return;
340 }
341
342 if (hat.mac.empty()) {
343 LOG(ERROR) << "Unable to set feature, invalid hat";
344 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
345 return;
346 }
347
348 auto features = FaceHalProperties::features();
349
350 auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
351 return *theFeature == (int)feature;
352 });
353
354 if (!enabled && (itr != features.end())) {
355 features.erase(itr);
356 } else if (enabled && (itr == features.end())) {
357 features.push_back((int)feature);
358 }
359
360 FaceHalProperties::features(features);
361 cb->onFeatureSet(feature);
362}
363
364void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
365 BEGIN_OP(0);
366 // If this is a weak HAL return 0 per the spec.
367 if (GetSensorStrength() != common::SensorStrength::STRONG) {
368 cb->onAuthenticatorIdRetrieved(0);
369 } else {
370 cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
371 }
372}
373
374void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
375 BEGIN_OP(0);
376 int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
377 int64_t newId = authenticatorId + 1;
378 FaceHalProperties::authenticator_id(newId);
379 cb->onAuthenticatorIdInvalidated(newId);
380}
381
382void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
383 const keymaster::HardwareAuthToken& /*hat*/) {
384 BEGIN_OP(0);
385 FaceHalProperties::lockout(false);
386 cb->onLockoutCleared();
387}
388
Jeff Pu484d2e72023-09-25 15:11:19 +0000389} // namespace aidl::android::hardware::biometrics::face