blob: dc524bbbcfbc8c8ebc69b81d6307bed55841d0a1 [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));
Joshua McCloskeydb009a52022-05-10 05:18:20 +000056
57 // Do proper HAT verification in the real implementation.
58 if (hat.mac.empty()) {
59 LOG(ERROR) << "Fail: hat";
60 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
61 return;
62 }
63
Jeff Pu84c60182023-12-04 16:53:04 +000064 // Format: <id>:<progress_ms-[acquiredInfo,...],...:<success>
65 // ------:-----------------------------------------:--------------
66 // | | |--->enrollment success (true/false)
67 // | |--> progress_steps
68 // |
69 // |-->enrollment id
70 //
71 //
72 // progress_steps
73 // <progress_duration>-[acquiredInfo,...]+
74 // ---------------------------- ---------------------
75 // | |-> sequence of acquiredInfo code
76 // | --> time duration of the step in ms
77 //
78 // E.g. 1:2000-[21,1108,5,6,1],1000-[1113,4,1]:true
79 // A success enrollement of id 1 by 2 steps
80 // 1st step lasts 2000ms with acquiredInfo codes (21,1108,5,6,1)
81 // 2nd step lasts 1000ms with acquiredInfo codes (1113,4,1)
82 //
83 std::string defaultNextEnrollment =
84 "1:1000-[21,7,1,1103],1500-[1108,1],2000-[1113,1],2500-[1118,1]:true";
85 auto nextEnroll = FaceHalProperties::next_enrollment().value_or(defaultNextEnrollment);
86 auto parts = Util::split(nextEnroll, ":");
87 if (parts.size() != 3) {
88 LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
Joshua McCloskeydb009a52022-05-10 05:18:20 +000089 cb->onError(Error::VENDOR, 0 /* vendorError */);
90 return;
91 }
Joshua McCloskeydb009a52022-05-10 05:18:20 +000092 auto enrollmentId = std::stoi(parts[0]);
Jeff Pu84c60182023-12-04 16:53:04 +000093 auto progress = Util::parseEnrollmentCapture(parts[1]);
94 for (size_t i = 0; i < progress.size(); i += 2) {
95 auto left = (progress.size() - i) / 2 - 1;
96 auto duration = progress[i][0];
97 auto acquired = progress[i + 1];
98 auto N = acquired.size();
Joshua McCloskeydb009a52022-05-10 05:18:20 +000099
Jeff Pu84c60182023-12-04 16:53:04 +0000100 for (int j = 0; j < N; j++) {
101 SLEEP_MS(duration / N);
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000102
Jeff Pu84c60182023-12-04 16:53:04 +0000103 if (shouldCancel(cancel)) {
104 LOG(ERROR) << "Fail: cancel";
105 cb->onError(Error::CANCELED, 0 /* vendorCode */);
106 return;
107 }
108 EnrollmentFrame frame = {};
109 auto ac = convertAcquiredInfo(acquired[j]);
110 frame.data.acquiredInfo = ac.first;
111 frame.data.vendorCode = ac.second;
112 frame.stage = (i == 0 && j == 0) ? EnrollmentStage::FIRST_FRAME_RECEIVED
113 : (i == progress.size() - 2 && j == N - 1)
114 ? EnrollmentStage::ENROLLMENT_FINISHED
115 : EnrollmentStage::WAITING_FOR_CENTERING;
116 cb->onEnrollmentFrame(frame);
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000117 }
118
Jeff Pu84c60182023-12-04 16:53:04 +0000119 if (left == 0 && !IS_TRUE(parts[2])) { // end and failed
120 LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
121 FaceHalProperties::next_enrollment({});
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000122 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
Jeff Pu84c60182023-12-04 16:53:04 +0000123 } else { // progress and update props if last time
124 LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
125 if (left == 0) {
126 auto enrollments = FaceHalProperties::enrollments();
127 enrollments.emplace_back(enrollmentId);
128 FaceHalProperties::enrollments(enrollments);
129 FaceHalProperties::next_enrollment({});
130 // change authenticatorId after new enrollment
131 auto id = FaceHalProperties::authenticator_id().value_or(0);
132 auto newId = id + 1;
133 FaceHalProperties::authenticator_id(newId);
134 LOG(INFO) << "Enrolled: " << enrollmentId;
135 }
136 cb->onEnrollmentProgress(enrollmentId, left);
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000137 }
138 }
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000139}
140
141void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
142 const std::future<void>& cancel) {
143 BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
144
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000145 auto id = FaceHalProperties::enrollment_hit().value_or(0);
146 auto enrolls = FaceHalProperties::enrollments();
147 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
Jeff Pu484d2e72023-09-25 15:11:19 +0000148
149 auto vec2str = [](std::vector<AcquiredInfo> va) {
150 std::stringstream ss;
151 bool isFirst = true;
152 for (auto ac : va) {
153 if (!isFirst) ss << ",";
154 ss << std::to_string((int8_t)ac);
155 isFirst = false;
156 }
157 return ss.str();
158 };
159
160 // default behavior mimic face sensor in U
161 int64_t defaultAuthDuration = 500;
162 std::string defaultAcquiredInfo =
163 vec2str({AcquiredInfo::START, AcquiredInfo::FIRST_FRAME_RECEIVED});
164 if (!isEnrolled) {
165 std::vector<AcquiredInfo> v;
166 for (int i = 0; i < 56; i++) v.push_back(AcquiredInfo::NOT_DETECTED);
167 defaultAcquiredInfo += "," + vec2str(v);
168 defaultAuthDuration = 2100;
169 } else {
170 defaultAcquiredInfo += "," + vec2str({AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
171 AcquiredInfo::TOO_BRIGHT, AcquiredInfo::TOO_BRIGHT,
172 AcquiredInfo::GOOD, AcquiredInfo::GOOD});
173 }
174
175 int64_t now = Util::getSystemNanoTime();
176 int64_t duration =
177 FaceHalProperties::operation_authenticate_duration().value_or(defaultAuthDuration);
178 auto acquired =
179 FaceHalProperties::operation_authenticate_acquired().value_or(defaultAcquiredInfo);
180 auto acquiredInfos = Util::parseIntSequence(acquired);
181 int N = acquiredInfos.size();
182
183 if (N == 0) {
184 LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000185 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
186 return;
187 }
188
Jeff Pu484d2e72023-09-25 15:11:19 +0000189 int i = 0;
190 do {
191 if (FaceHalProperties::lockout().value_or(false)) {
192 LOG(ERROR) << "Fail: lockout";
193 cb->onLockoutPermanent();
194 cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
195 return;
196 }
197
198 if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
199 LOG(ERROR) << "Fail: operation_authenticate_fails";
200 cb->onAuthenticationFailed();
201 return;
202 }
203
204 auto err = FaceHalProperties::operation_authenticate_error().value_or(0);
205 if (err != 0) {
206 LOG(ERROR) << "Fail: operation_authenticate_error";
207 auto ec = convertError(err);
208 cb->onError(ec.first, ec.second);
209 return; /* simply terminating current operation for any user inserted error,
210 revisit if tests need*/
211 }
212
213 if (shouldCancel(cancel)) {
214 LOG(ERROR) << "Fail: cancel";
215 cb->onError(Error::CANCELED, 0 /* vendorCode */);
216 return;
217 }
218
219 if (i < N) {
220 auto ac = convertAcquiredInfo(acquiredInfos[i]);
221 AuthenticationFrame frame;
222 frame.data.acquiredInfo = ac.first;
223 frame.data.vendorCode = ac.second;
224 cb->onAuthenticationFrame(frame);
225 LOG(INFO) << "AcquiredInfo:" << i << ": (" << (int)ac.first << "," << (int)ac.second
226 << ")";
227 i++;
228 }
229
230 SLEEP_MS(duration / N);
231 } while (!Util::hasElapsed(now, duration));
232
233 if (id > 0 && isEnrolled) {
234 cb->onAuthenticationSucceeded(id, {} /* hat */);
235 return;
236 } else {
237 LOG(ERROR) << "Fail: face not enrolled";
238 cb->onAuthenticationFailed();
239 cb->onError(Error::TIMEOUT, 0 /* vendorError*/);
240 return;
241 }
242}
243
244std::pair<AcquiredInfo, int32_t> FakeFaceEngine::convertAcquiredInfo(int32_t code) {
245 std::pair<AcquiredInfo, int32_t> res;
246 if (code > FACE_ACQUIRED_VENDOR_BASE) {
247 res.first = AcquiredInfo::VENDOR;
248 res.second = code - FACE_ACQUIRED_VENDOR_BASE;
249 } else {
250 res.first = (AcquiredInfo)code;
251 res.second = 0;
252 }
253 return res;
254}
255
256std::pair<Error, int32_t> FakeFaceEngine::convertError(int32_t code) {
257 std::pair<Error, int32_t> res;
258 if (code > FACE_ERROR_VENDOR_BASE) {
259 res.first = Error::VENDOR;
260 res.second = code - FACE_ERROR_VENDOR_BASE;
261 } else {
262 res.first = (Error)code;
263 res.second = 0;
264 }
265 return res;
Joshua McCloskeydb009a52022-05-10 05:18:20 +0000266}
267
268void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
269 BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
270
271 if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
272 LOG(ERROR) << "Fail: operation_detect_interaction_fails";
273 cb->onError(Error::VENDOR, 0 /* vendorError */);
274 return;
275 }
276
277 if (shouldCancel(cancel)) {
278 LOG(ERROR) << "Fail: cancel";
279 cb->onError(Error::CANCELED, 0 /* vendorCode */);
280 return;
281 }
282
283 auto id = FaceHalProperties::enrollment_hit().value_or(0);
284 auto enrolls = FaceHalProperties::enrollments();
285 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
286 if (id <= 0 || !isEnrolled) {
287 LOG(ERROR) << "Fail: not enrolled";
288 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
289 return;
290 }
291
292 cb->onInteractionDetected();
293}
294
295void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
296 BEGIN_OP(0);
297 std::vector<int32_t> enrollments;
298 for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
299 if (enrollmentId) {
300 enrollments.push_back(*enrollmentId);
301 }
302 }
303 cb->onEnrollmentsEnumerated(enrollments);
304}
305
306void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
307 const std::vector<int32_t>& enrollmentIds) {
308 BEGIN_OP(0);
309
310 std::vector<std::optional<int32_t>> newEnrollments;
311 for (const auto& enrollment : FaceHalProperties::enrollments()) {
312 auto id = enrollment.value_or(0);
313 if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
314 newEnrollments.emplace_back(id);
315 }
316 }
317 FaceHalProperties::enrollments(newEnrollments);
318 cb->onEnrollmentsRemoved(enrollmentIds);
319}
320
321void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
322 BEGIN_OP(0);
323
324 if (FaceHalProperties::enrollments().empty()) {
325 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
326 return;
327 }
328
329 std::vector<Feature> featuresToReturn = {};
330 for (const auto& feature : FaceHalProperties::features()) {
331 if (feature) {
332 featuresToReturn.push_back((Feature)(*feature));
333 }
334 }
335 cb->onFeaturesRetrieved(featuresToReturn);
336}
337
338void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
339 Feature feature, bool enabled) {
340 BEGIN_OP(0);
341
342 if (FaceHalProperties::enrollments().empty()) {
343 LOG(ERROR) << "Unable to set feature, enrollments are empty";
344 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
345 return;
346 }
347
348 if (hat.mac.empty()) {
349 LOG(ERROR) << "Unable to set feature, invalid hat";
350 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
351 return;
352 }
353
354 auto features = FaceHalProperties::features();
355
356 auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
357 return *theFeature == (int)feature;
358 });
359
360 if (!enabled && (itr != features.end())) {
361 features.erase(itr);
362 } else if (enabled && (itr == features.end())) {
363 features.push_back((int)feature);
364 }
365
366 FaceHalProperties::features(features);
367 cb->onFeatureSet(feature);
368}
369
370void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
371 BEGIN_OP(0);
372 // If this is a weak HAL return 0 per the spec.
373 if (GetSensorStrength() != common::SensorStrength::STRONG) {
374 cb->onAuthenticatorIdRetrieved(0);
375 } else {
376 cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
377 }
378}
379
380void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
381 BEGIN_OP(0);
382 int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
383 int64_t newId = authenticatorId + 1;
384 FaceHalProperties::authenticator_id(newId);
385 cb->onAuthenticatorIdInvalidated(newId);
386}
387
388void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
389 const keymaster::HardwareAuthToken& /*hat*/) {
390 BEGIN_OP(0);
391 FaceHalProperties::lockout(false);
392 cb->onLockoutCleared();
393}
394
Jeff Pu484d2e72023-09-25 15:11:19 +0000395} // namespace aidl::android::hardware::biometrics::face