blob: 0f088f4331a61bec8e6e3920cd1eaba051cd86f4 [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
139 // Signal to the framework that we have begun authenticating.
140 AuthenticationFrame frame;
141 frame.data.acquiredInfo = AcquiredInfo::START;
142 frame.data.vendorCode = 0;
143 cb->onAuthenticationFrame(frame);
144
145 // Also signal that we have opened the camera.
146 frame = {};
147 frame.data.acquiredInfo = AcquiredInfo::FIRST_FRAME_RECEIVED;
148 frame.data.vendorCode = 0;
149 cb->onAuthenticationFrame(frame);
150
151 auto now = Util::getSystemNanoTime();
152 int64_t duration = FaceHalProperties::operation_authenticate_duration().value_or(0);
153 if (duration > 0) {
154 do {
155 SLEEP_MS(5);
156 } while (!Util::hasElapsed(now, duration));
157 }
158
159 if (FaceHalProperties::operation_authenticate_fails().value_or(false)) {
160 LOG(ERROR) << "Fail: operation_authenticate_fails";
161 cb->onError(Error::VENDOR, 0 /* vendorError */);
162 return;
163 }
164
165 if (FaceHalProperties::lockout().value_or(false)) {
166 LOG(ERROR) << "Fail: lockout";
167 cb->onLockoutPermanent();
168 cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
169 return;
170 }
171
172 if (shouldCancel(cancel)) {
173 LOG(ERROR) << "Fail: cancel";
174 cb->onError(Error::CANCELED, 0 /* vendorCode */);
175 return;
176 }
177
178 auto id = FaceHalProperties::enrollment_hit().value_or(0);
179 auto enrolls = FaceHalProperties::enrollments();
180 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
181 if (id < 0 || !isEnrolled) {
182 LOG(ERROR) << (isEnrolled ? "invalid enrollment hit" : "Fail: not enrolled");
183 cb->onAuthenticationFailed();
184 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
185 return;
186 }
187
188 cb->onAuthenticationSucceeded(id, {} /* hat */);
189}
190
191void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
192 BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
193
194 if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
195 LOG(ERROR) << "Fail: operation_detect_interaction_fails";
196 cb->onError(Error::VENDOR, 0 /* vendorError */);
197 return;
198 }
199
200 if (shouldCancel(cancel)) {
201 LOG(ERROR) << "Fail: cancel";
202 cb->onError(Error::CANCELED, 0 /* vendorCode */);
203 return;
204 }
205
206 auto id = FaceHalProperties::enrollment_hit().value_or(0);
207 auto enrolls = FaceHalProperties::enrollments();
208 auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
209 if (id <= 0 || !isEnrolled) {
210 LOG(ERROR) << "Fail: not enrolled";
211 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
212 return;
213 }
214
215 cb->onInteractionDetected();
216}
217
218void FakeFaceEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
219 BEGIN_OP(0);
220 std::vector<int32_t> enrollments;
221 for (const auto& enrollmentId : FaceHalProperties::enrollments()) {
222 if (enrollmentId) {
223 enrollments.push_back(*enrollmentId);
224 }
225 }
226 cb->onEnrollmentsEnumerated(enrollments);
227}
228
229void FakeFaceEngine::removeEnrollmentsImpl(ISessionCallback* cb,
230 const std::vector<int32_t>& enrollmentIds) {
231 BEGIN_OP(0);
232
233 std::vector<std::optional<int32_t>> newEnrollments;
234 for (const auto& enrollment : FaceHalProperties::enrollments()) {
235 auto id = enrollment.value_or(0);
236 if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) == enrollmentIds.end()) {
237 newEnrollments.emplace_back(id);
238 }
239 }
240 FaceHalProperties::enrollments(newEnrollments);
241 cb->onEnrollmentsRemoved(enrollmentIds);
242}
243
244void FakeFaceEngine::getFeaturesImpl(ISessionCallback* cb) {
245 BEGIN_OP(0);
246
247 if (FaceHalProperties::enrollments().empty()) {
248 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
249 return;
250 }
251
252 std::vector<Feature> featuresToReturn = {};
253 for (const auto& feature : FaceHalProperties::features()) {
254 if (feature) {
255 featuresToReturn.push_back((Feature)(*feature));
256 }
257 }
258 cb->onFeaturesRetrieved(featuresToReturn);
259}
260
261void FakeFaceEngine::setFeatureImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
262 Feature feature, bool enabled) {
263 BEGIN_OP(0);
264
265 if (FaceHalProperties::enrollments().empty()) {
266 LOG(ERROR) << "Unable to set feature, enrollments are empty";
267 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
268 return;
269 }
270
271 if (hat.mac.empty()) {
272 LOG(ERROR) << "Unable to set feature, invalid hat";
273 cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
274 return;
275 }
276
277 auto features = FaceHalProperties::features();
278
279 auto itr = std::find_if(features.begin(), features.end(), [feature](const auto& theFeature) {
280 return *theFeature == (int)feature;
281 });
282
283 if (!enabled && (itr != features.end())) {
284 features.erase(itr);
285 } else if (enabled && (itr == features.end())) {
286 features.push_back((int)feature);
287 }
288
289 FaceHalProperties::features(features);
290 cb->onFeatureSet(feature);
291}
292
293void FakeFaceEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
294 BEGIN_OP(0);
295 // If this is a weak HAL return 0 per the spec.
296 if (GetSensorStrength() != common::SensorStrength::STRONG) {
297 cb->onAuthenticatorIdRetrieved(0);
298 } else {
299 cb->onAuthenticatorIdRetrieved(FaceHalProperties::authenticator_id().value_or(0));
300 }
301}
302
303void FakeFaceEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
304 BEGIN_OP(0);
305 int64_t authenticatorId = FaceHalProperties::authenticator_id().value_or(0);
306 int64_t newId = authenticatorId + 1;
307 FaceHalProperties::authenticator_id(newId);
308 cb->onAuthenticatorIdInvalidated(newId);
309}
310
311void FakeFaceEngine::resetLockoutImpl(ISessionCallback* cb,
312 const keymaster::HardwareAuthToken& /*hat*/) {
313 BEGIN_OP(0);
314 FaceHalProperties::lockout(false);
315 cb->onLockoutCleared();
316}
317
318} // namespace aidl::android::hardware::biometrics::face