• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 <android/binder_process.h>
18 #include <face.sysprop.h>
19 #include <gtest/gtest.h>
20 
21 #include <aidl/android/hardware/biometrics/face/BnSessionCallback.h>
22 #include <android-base/logging.h>
23 
24 #include "FakeFaceEngine.h"
25 
26 using namespace ::android::face::virt;
27 using namespace ::aidl::android::hardware::biometrics::face;
28 using namespace ::aidl::android::hardware::keymaster;
29 
30 namespace aidl::android::hardware::biometrics::face {
31 
32 class TestSessionCallback : public BnSessionCallback {
33   public:
onChallengeGenerated(int64_t challenge)34     ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
35         mLastChallenge = challenge;
36         return ndk::ScopedAStatus::ok();
37     };
onChallengeRevoked(int64_t challenge)38     ::ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
39         mLastChallengeRevoked = challenge;
40         return ndk::ScopedAStatus::ok();
41     };
onError(Error error,int32_t)42     ::ndk::ScopedAStatus onError(Error error, int32_t) override {
43         mError = error;
44         return ndk::ScopedAStatus::ok();
45     };
onEnrollmentProgress(int32_t enrollmentId,int32_t remaining)46     ::ndk::ScopedAStatus onEnrollmentProgress(int32_t enrollmentId, int32_t remaining) override {
47         if (remaining == 0) mLastEnrolled = enrollmentId;
48         return ndk::ScopedAStatus::ok();
49     };
50 
onAuthenticationSucceeded(int32_t enrollmentId,const HardwareAuthToken &)51     ::ndk::ScopedAStatus onAuthenticationSucceeded(int32_t enrollmentId,
52                                                    const HardwareAuthToken&) override {
53         mLastAuthenticated = enrollmentId;
54         mAuthenticateFailed = false;
55         return ndk::ScopedAStatus::ok();
56     };
onAuthenticationFailed()57     ::ndk::ScopedAStatus onAuthenticationFailed() override {
58         mLastAuthenticated = 0;
59         mAuthenticateFailed = true;
60         return ndk::ScopedAStatus::ok();
61     };
onInteractionDetected()62     ::ndk::ScopedAStatus onInteractionDetected() override {
63         mInteractionDetectedCount++;
64         return ndk::ScopedAStatus::ok();
65     };
66 
onEnrollmentFrame(const EnrollmentFrame & frame)67     ::ndk::ScopedAStatus onEnrollmentFrame(const EnrollmentFrame& frame) override {
68         mEnrollmentFrames.push_back(frame.data.vendorCode);
69         return ndk::ScopedAStatus::ok();
70     }
71 
onEnrollmentsEnumerated(const std::vector<int32_t> & enrollmentIds)72     ::ndk::ScopedAStatus onEnrollmentsEnumerated(
73             const std::vector<int32_t>& enrollmentIds) override {
74         mLastEnrollmentsEnumerated = enrollmentIds;
75         return ndk::ScopedAStatus::ok();
76     };
onEnrollmentsRemoved(const std::vector<int32_t> & enrollmentIds)77     ::ndk::ScopedAStatus onEnrollmentsRemoved(const std::vector<int32_t>& enrollmentIds) override {
78         mLastEnrollmentRemoved = enrollmentIds;
79         return ndk::ScopedAStatus::ok();
80     };
onAuthenticatorIdRetrieved(int64_t authenticatorId)81     ::ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t authenticatorId) override {
82         mLastAuthenticatorId = authenticatorId;
83         return ndk::ScopedAStatus::ok();
84     };
onAuthenticatorIdInvalidated(int64_t authenticatorId)85     ::ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t authenticatorId) override {
86         mLastAuthenticatorId = authenticatorId;
87         mAuthenticatorIdInvalidated = true;
88         return ndk::ScopedAStatus::ok();
89     };
onAuthenticationFrame(const AuthenticationFrame &)90     ::ndk::ScopedAStatus onAuthenticationFrame(const AuthenticationFrame& /*authFrame*/) override {
91         return ndk::ScopedAStatus::ok();
92     }
onLockoutPermanent()93     ::ndk::ScopedAStatus onLockoutPermanent() override {
94         mLockoutPermanent = true;
95         return ndk::ScopedAStatus::ok();
96     };
onLockoutTimed(int64_t)97     ::ndk::ScopedAStatus onLockoutTimed(int64_t /* timeout */) override {
98         return ndk::ScopedAStatus::ok();
99     }
onLockoutCleared()100     ::ndk::ScopedAStatus onLockoutCleared() override {
101         mLockoutPermanent = false;
102         return ndk::ScopedAStatus::ok();
103     }
onSessionClosed()104     ::ndk::ScopedAStatus onSessionClosed() override { return ndk::ScopedAStatus::ok(); }
105 
onFeaturesRetrieved(const std::vector<Feature> & features)106     ::ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& features) override {
107         mFeatures = features;
108         return ndk::ScopedAStatus::ok();
109     }
110 
onFeatureSet(Feature feature)111     ::ndk::ScopedAStatus onFeatureSet(Feature feature) override {
112         mLastFeatureSet = feature;
113         return ndk::ScopedAStatus::ok();
114     }
115 
116     Error mError = Error::UNKNOWN;
117     int64_t mLastChallenge = -1;
118     int64_t mLastChallengeRevoked = -1;
119     int32_t mLastEnrolled = -1;
120     int32_t mLastAuthenticated = -1;
121     int64_t mLastAuthenticatorId = -1;
122     std::vector<int32_t> mLastEnrollmentsEnumerated;
123     std::vector<int32_t> mLastEnrollmentRemoved;
124     std::vector<Feature> mFeatures;
125     Feature mLastFeatureSet;
126     std::vector<int32_t> mEnrollmentFrames;
127     bool mAuthenticateFailed = false;
128     bool mAuthenticatorIdInvalidated = false;
129     bool mLockoutPermanent = false;
130     int mInteractionDetectedCount = 0;
131 };
132 
133 class FakeFaceEngineTest : public ::testing::Test {
134   protected:
SetUp()135     void SetUp() override {
136         LOG(ERROR) << "JRM SETUP";
137         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
138         FaceHalProperties::enrollments({});
139         FaceHalProperties::challenge({});
140         FaceHalProperties::features({});
141         FaceHalProperties::authenticator_id({});
142         FaceHalProperties::strength("");
143     }
144 
145     FakeFaceEngine mEngine;
146     std::shared_ptr<TestSessionCallback> mCallback;
147     std::promise<void> mCancel;
148 };
149 
TEST_F(FakeFaceEngineTest,one_eq_one)150 TEST_F(FakeFaceEngineTest, one_eq_one) {
151     ASSERT_EQ(1, 1);
152 }
153 
TEST_F(FakeFaceEngineTest,GenerateChallenge)154 TEST_F(FakeFaceEngineTest, GenerateChallenge) {
155     mEngine.generateChallengeImpl(mCallback.get());
156     ASSERT_EQ(FaceHalProperties::challenge().value(), mCallback->mLastChallenge);
157 }
158 
TEST_F(FakeFaceEngineTest,RevokeChallenge)159 TEST_F(FakeFaceEngineTest, RevokeChallenge) {
160     auto challenge = FaceHalProperties::challenge().value_or(10);
161     mEngine.revokeChallengeImpl(mCallback.get(), challenge);
162     ASSERT_FALSE(FaceHalProperties::challenge().has_value());
163     ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
164 }
165 
TEST_F(FakeFaceEngineTest,ResetLockout)166 TEST_F(FakeFaceEngineTest, ResetLockout) {
167     FaceHalProperties::lockout(true);
168     mEngine.resetLockoutImpl(mCallback.get(), {});
169     ASSERT_FALSE(mCallback->mLockoutPermanent);
170     ASSERT_FALSE(FaceHalProperties::lockout().value_or(true));
171 }
172 
TEST_F(FakeFaceEngineTest,AuthenticatorId)173 TEST_F(FakeFaceEngineTest, AuthenticatorId) {
174     FaceHalProperties::authenticator_id(50);
175     mEngine.getAuthenticatorIdImpl(mCallback.get());
176     ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
177     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
178 }
179 
TEST_F(FakeFaceEngineTest,GetAuthenticatorIdWeakReturnsZero)180 TEST_F(FakeFaceEngineTest, GetAuthenticatorIdWeakReturnsZero) {
181     FaceHalProperties::strength("weak");
182     FaceHalProperties::authenticator_id(500);
183     mEngine.getAuthenticatorIdImpl(mCallback.get());
184     ASSERT_EQ(0, mCallback->mLastAuthenticatorId);
185     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
186 }
187 
TEST_F(FakeFaceEngineTest,AuthenticatorIdInvalidate)188 TEST_F(FakeFaceEngineTest, AuthenticatorIdInvalidate) {
189     FaceHalProperties::authenticator_id(500);
190     mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
191     ASSERT_NE(500, FaceHalProperties::authenticator_id().value());
192     ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
193 }
194 
TEST_F(FakeFaceEngineTest,Enroll)195 TEST_F(FakeFaceEngineTest, Enroll) {
196     FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:true");
197     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
198     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
199                        mCancel.get_future());
200     ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
201     ASSERT_EQ(1, FaceHalProperties::enrollments().size());
202     ASSERT_EQ(1, FaceHalProperties::enrollments()[0].value());
203     ASSERT_EQ(1, mCallback->mLastEnrolled);
204 }
205 
TEST_F(FakeFaceEngineTest,EnrollFails)206 TEST_F(FakeFaceEngineTest, EnrollFails) {
207     FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
208     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
209     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
210                        mCancel.get_future());
211     ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
212     ASSERT_EQ(0, FaceHalProperties::enrollments().size());
213 }
214 
TEST_F(FakeFaceEngineTest,EnrollCancel)215 TEST_F(FakeFaceEngineTest, EnrollCancel) {
216     FaceHalProperties::next_enrollment("1,0:30:true,1:0:true,2:0:true,3:0:true,4:0:false");
217     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
218     mCancel.set_value();
219     mEngine.enrollImpl(mCallback.get(), hat, {} /*enrollmentType*/, {} /*features*/,
220                        mCancel.get_future());
221     ASSERT_EQ(Error::CANCELED, mCallback->mError);
222     ASSERT_EQ(-1, mCallback->mLastEnrolled);
223     ASSERT_EQ(0, FaceHalProperties::enrollments().size());
224     ASSERT_FALSE(FaceHalProperties::next_enrollment().has_value());
225 }
226 
TEST_F(FakeFaceEngineTest,Authenticate)227 TEST_F(FakeFaceEngineTest, Authenticate) {
228     FaceHalProperties::enrollments({100});
229     FaceHalProperties::enrollment_hit(100);
230     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
231 
232     ASSERT_EQ(100, mCallback->mLastAuthenticated);
233     ASSERT_FALSE(mCallback->mAuthenticateFailed);
234 }
235 
TEST_F(FakeFaceEngineTest,AuthenticateCancel)236 TEST_F(FakeFaceEngineTest, AuthenticateCancel) {
237     FaceHalProperties::enrollments({100});
238     FaceHalProperties::enrollment_hit(100);
239     mCancel.set_value();
240     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
241     ASSERT_EQ(Error::CANCELED, mCallback->mError);
242 }
243 
TEST_F(FakeFaceEngineTest,AuthenticateFailedForUnEnrolled)244 TEST_F(FakeFaceEngineTest, AuthenticateFailedForUnEnrolled) {
245     FaceHalProperties::enrollments({3});
246     FaceHalProperties::enrollment_hit(100);
247     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, mCancel.get_future());
248     ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
249     ASSERT_TRUE(mCallback->mAuthenticateFailed);
250 }
251 
TEST_F(FakeFaceEngineTest,DetectInteraction)252 TEST_F(FakeFaceEngineTest, DetectInteraction) {
253     FaceHalProperties::enrollments({100});
254     FaceHalProperties::enrollment_hit(100);
255     ASSERT_EQ(0, mCallback->mInteractionDetectedCount);
256     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
257     ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
258 }
259 
TEST_F(FakeFaceEngineTest,DetectInteractionCancel)260 TEST_F(FakeFaceEngineTest, DetectInteractionCancel) {
261     FaceHalProperties::enrollments({100});
262     FaceHalProperties::enrollment_hit(100);
263     mCancel.set_value();
264     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
265     ASSERT_EQ(Error::CANCELED, mCallback->mError);
266 }
267 
TEST_F(FakeFaceEngineTest,GetFeatureEmpty)268 TEST_F(FakeFaceEngineTest, GetFeatureEmpty) {
269     mEngine.getFeaturesImpl(mCallback.get());
270     ASSERT_TRUE(mCallback->mFeatures.empty());
271 }
272 
TEST_F(FakeFaceEngineTest,SetFeature)273 TEST_F(FakeFaceEngineTest, SetFeature) {
274     FaceHalProperties::enrollments({1});
275     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
276     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
277     auto features = mCallback->mFeatures;
278     ASSERT_TRUE(features.empty());
279     ASSERT_EQ(Feature::REQUIRE_ATTENTION, mCallback->mLastFeatureSet);
280 
281     mEngine.getFeaturesImpl(mCallback.get());
282     features = mCallback->mFeatures;
283     ASSERT_FALSE(features.empty());
284     ASSERT_NE(features.end(),
285               std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
286 }
287 
TEST_F(FakeFaceEngineTest,ToggleFeature)288 TEST_F(FakeFaceEngineTest, ToggleFeature) {
289     FaceHalProperties::enrollments({1});
290     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
291     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
292     mEngine.getFeaturesImpl(mCallback.get());
293     auto features = mCallback->mFeatures;
294     ASSERT_FALSE(features.empty());
295     ASSERT_NE(features.end(),
296               std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
297 
298     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
299     mEngine.getFeaturesImpl(mCallback.get());
300     features = mCallback->mFeatures;
301     ASSERT_TRUE(features.empty());
302 }
303 
TEST_F(FakeFaceEngineTest,TurningOffNonExistentFeatureDoesNothing)304 TEST_F(FakeFaceEngineTest, TurningOffNonExistentFeatureDoesNothing) {
305     FaceHalProperties::enrollments({1});
306     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
307     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, false);
308     mEngine.getFeaturesImpl(mCallback.get());
309     auto features = mCallback->mFeatures;
310     ASSERT_TRUE(features.empty());
311 }
312 
TEST_F(FakeFaceEngineTest,SetMultipleFeatures)313 TEST_F(FakeFaceEngineTest, SetMultipleFeatures) {
314     FaceHalProperties::enrollments({1});
315     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
316     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
317     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
318     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
319     mEngine.getFeaturesImpl(mCallback.get());
320     auto features = mCallback->mFeatures;
321     ASSERT_EQ(3, features.size());
322     ASSERT_NE(features.end(),
323               std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
324     ASSERT_NE(features.end(),
325               std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
326     ASSERT_NE(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
327 }
328 
TEST_F(FakeFaceEngineTest,SetMultipleFeaturesAndTurnOffSome)329 TEST_F(FakeFaceEngineTest, SetMultipleFeaturesAndTurnOffSome) {
330     FaceHalProperties::enrollments({1});
331     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
332     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_ATTENTION, true);
333     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::REQUIRE_DIVERSE_POSES, true);
334     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, true);
335     mEngine.setFeatureImpl(mCallback.get(), hat, Feature::DEBUG, false);
336     mEngine.getFeaturesImpl(mCallback.get());
337     auto features = mCallback->mFeatures;
338     ASSERT_EQ(2, features.size());
339     ASSERT_NE(features.end(),
340               std::find(features.begin(), features.end(), Feature::REQUIRE_ATTENTION));
341     ASSERT_NE(features.end(),
342               std::find(features.begin(), features.end(), Feature::REQUIRE_DIVERSE_POSES));
343     ASSERT_EQ(features.end(), std::find(features.begin(), features.end(), Feature::DEBUG));
344 }
345 
TEST_F(FakeFaceEngineTest,Enumerate)346 TEST_F(FakeFaceEngineTest, Enumerate) {
347     FaceHalProperties::enrollments({120, 3});
348     mEngine.enumerateEnrollmentsImpl(mCallback.get());
349     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
350     ASSERT_FALSE(enrolls.empty());
351     ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
352     ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
353 }
354 
TEST_F(FakeFaceEngineTest,RemoveEnrollments)355 TEST_F(FakeFaceEngineTest, RemoveEnrollments) {
356     FaceHalProperties::enrollments({120, 3, 100});
357     mEngine.removeEnrollmentsImpl(mCallback.get(), {120, 100});
358     mEngine.enumerateEnrollmentsImpl(mCallback.get());
359     auto enrolls = mCallback->mLastEnrollmentsEnumerated;
360     ASSERT_FALSE(enrolls.empty());
361     ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 120));
362     ASSERT_NE(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 3));
363     ASSERT_EQ(enrolls.end(), std::find(enrolls.begin(), enrolls.end(), 100));
364 }
365 
TEST_F(FakeFaceEngineTest,ResetLockoutWithAuth)366 TEST_F(FakeFaceEngineTest, ResetLockoutWithAuth) {
367     FaceHalProperties::lockout(true);
368     FaceHalProperties::enrollments({33});
369     FaceHalProperties::enrollment_hit(33);
370     auto cancelFuture = mCancel.get_future();
371     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
372 
373     ASSERT_TRUE(mCallback->mLockoutPermanent);
374 
375     mEngine.resetLockoutImpl(mCallback.get(), {} /* hat */);
376     ASSERT_FALSE(mCallback->mLockoutPermanent);
377     FaceHalProperties::enrollment_hit(33);
378     mEngine.authenticateImpl(mCallback.get(), 0 /* operationId*/, cancelFuture);
379     ASSERT_EQ(33, mCallback->mLastAuthenticated);
380     ASSERT_FALSE(mCallback->mAuthenticateFailed);
381 }
382 
383 }  // namespace aidl::android::hardware::biometrics::face