• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 #define LOG_TAG "biometrics_face_hidl_hal_test"
18 
19 #include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
20 #include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
21 
22 #include <VtsHalHidlTargetCallbackBase.h>
23 #include <VtsHalHidlTargetTestBase.h>
24 #include <VtsHalHidlTargetTestEnvBase.h>
25 #include <android-base/logging.h>
26 
27 #include <chrono>
28 #include <cstdint>
29 #include <random>
30 
31 using android::sp;
32 using android::hardware::hidl_vec;
33 using android::hardware::Return;
34 using android::hardware::Void;
35 using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
36 using android::hardware::biometrics::face::V1_0::FaceError;
37 using android::hardware::biometrics::face::V1_0::Feature;
38 using android::hardware::biometrics::face::V1_0::IBiometricsFace;
39 using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
40 using android::hardware::biometrics::face::V1_0::OptionalBool;
41 using android::hardware::biometrics::face::V1_0::OptionalUint64;
42 using android::hardware::biometrics::face::V1_0::Status;
43 
44 namespace {
45 
46 // Arbitrary, nonexistent userId
47 constexpr uint32_t kUserId = 9;
48 // Arbitrary, nonexistent faceId
49 constexpr uint32_t kFaceId = 5;
50 constexpr uint32_t kTimeoutSec = 3;
51 constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec);
52 constexpr int kGenerateChallengeIterations = 10;
53 constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata";
54 constexpr char kCallbackNameOnEnrollResult[] = "onEnrollResult";
55 constexpr char kCallbackNameOnAuthenticated[] = "onAuthenticated";
56 constexpr char kCallbackNameOnAcquired[] = "onAcquired";
57 constexpr char kCallbackNameOnError[] = "onError";
58 constexpr char kCallbackNameOnRemoved[] = "onRemoved";
59 constexpr char kCallbackNameOnEnumerate[] = "onEnumerate";
60 constexpr char kCallbackNameOnLockoutChanged[] = "onLockoutChanged";
61 
62 // Callback arguments that need to be captured for the tests.
63 struct FaceCallbackArgs {
64     // The error passed to the last onError() callback.
65     FaceError error;
66 
67     // The userId passed to the last onRemoved() callback.
68     int32_t userId;
69 };
70 
71 // Test callback class for the BiometricsFace HAL.
72 // The HAL will call these callback methods to notify about completed operations
73 // or encountered errors.
74 class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
75                      public IBiometricsFaceClientCallback {
76   public:
onEnrollResult(uint64_t,uint32_t,int32_t,uint32_t)77     Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override {
78         NotifyFromCallback(kCallbackNameOnEnrollResult);
79         return Void();
80     }
81 
onAuthenticated(uint64_t,uint32_t,int32_t,const hidl_vec<uint8_t> &)82     Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
83         NotifyFromCallback(kCallbackNameOnAuthenticated);
84         return Void();
85     }
86 
onAcquired(uint64_t,int32_t,FaceAcquiredInfo,int32_t)87     Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
88         NotifyFromCallback(kCallbackNameOnAcquired);
89         return Void();
90     }
91 
onError(uint64_t,int32_t,FaceError error,int32_t)92     Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
93         FaceCallbackArgs args = {};
94         args.error = error;
95         NotifyFromCallback(kCallbackNameOnError, args);
96         return Void();
97     }
98 
onRemoved(uint64_t,const hidl_vec<uint32_t> &,int32_t userId)99     Return<void> onRemoved(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
100         FaceCallbackArgs args = {};
101         args.userId = userId;
102         NotifyFromCallback(kCallbackNameOnRemoved, args);
103         return Void();
104     }
105 
onEnumerate(uint64_t,const hidl_vec<uint32_t> &,int32_t)106     Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
107         NotifyFromCallback(kCallbackNameOnEnumerate);
108         return Void();
109     }
110 
onLockoutChanged(uint64_t)111     Return<void> onLockoutChanged(uint64_t) override {
112         NotifyFromCallback(kCallbackNameOnLockoutChanged);
113         return Void();
114     }
115 };
116 
117 // Test environment for the BiometricsFace HAL.
118 class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
119   public:
120     // Get the test environment singleton.
Instance()121     static FaceHidlEnvironment* Instance() {
122         static FaceHidlEnvironment* instance = new FaceHidlEnvironment;
123         return instance;
124     }
125 
registerTestServices()126     void registerTestServices() override { registerTestService<IBiometricsFace>(); }
127 
128   private:
129     FaceHidlEnvironment() = default;
130 };
131 
132 // Test class for the BiometricsFace HAL.
133 class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
134   public:
SetUp()135     void SetUp() override {
136         mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFace>(
137                 FaceHidlEnvironment::Instance()->getServiceName<IBiometricsFace>());
138         ASSERT_NE(mService, nullptr);
139         mCallback = new FaceCallback();
140         mCallback->SetWaitTimeoutDefault(kTimeout);
141         Return<void> ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) {
142             ASSERT_EQ(Status::OK, res.status);
143             // Makes sure the "deviceId" represented by "res.value" is not 0.
144             // 0 would mean the HIDL is not available.
145             ASSERT_NE(0UL, res.value);
146         });
147         ASSERT_TRUE(ret1.isOk());
148         Return<Status> ret2 = mService->setActiveUser(kUserId, kFacedataDir);
149         ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
150     }
151 
TearDown()152     void TearDown() override {}
153 
154     sp<IBiometricsFace> mService;
155     sp<FaceCallback> mCallback;
156 };
157 
158 // generateChallenge should always return a unique, cryptographically secure,
159 // non-zero number.
TEST_F(FaceHidlTest,GenerateChallengeTest)160 TEST_F(FaceHidlTest, GenerateChallengeTest) {
161     std::map<uint64_t, int> m;
162     for (int i = 0; i < kGenerateChallengeIterations; ++i) {
163         Return<void> ret =
164                 mService->generateChallenge(kTimeoutSec, [&m](const OptionalUint64& res) {
165                     ASSERT_EQ(Status::OK, res.status);
166                     EXPECT_NE(0UL, res.value);
167                     m[res.value]++;
168                     EXPECT_EQ(1UL, m[res.value]);
169                 });
170         ASSERT_TRUE(ret.isOk());
171     }
172 }
173 
174 // enroll with an invalid (all zeroes) HAT should fail.
TEST_F(FaceHidlTest,EnrollZeroHatTest)175 TEST_F(FaceHidlTest, EnrollZeroHatTest) {
176     // Filling HAT with zeros
177     hidl_vec<uint8_t> token(69);
178     for (size_t i = 0; i < 69; i++) {
179         token[i] = 0;
180     }
181 
182     Return<Status> ret = mService->enroll(token, kTimeoutSec, {});
183     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
184 
185     // onError should be called with a meaningful (nonzero) error.
186     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
187     EXPECT_TRUE(res.no_timeout);
188     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
189 }
190 
191 // enroll with an invalid HAT should fail.
TEST_F(FaceHidlTest,EnrollGarbageHatTest)192 TEST_F(FaceHidlTest, EnrollGarbageHatTest) {
193     // Filling HAT with pseudorandom invalid data.
194     // Using default seed to make the test reproducible.
195     std::mt19937 gen(std::mt19937::default_seed);
196     std::uniform_int_distribution<uint8_t> dist;
197     hidl_vec<uint8_t> token(69);
198     for (size_t i = 0; i < 69; ++i) {
199         token[i] = dist(gen);
200     }
201 
202     Return<Status> ret = mService->enroll(token, kTimeoutSec, {});
203     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
204 
205     // onError should be called with a meaningful (nonzero) error.
206     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
207     EXPECT_TRUE(res.no_timeout);
208     EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
209 }
210 
211 // setFeature with an invalid (all zeros) HAT should fail.
TEST_F(FaceHidlTest,SetFeatureZeroHatTest)212 TEST_F(FaceHidlTest, SetFeatureZeroHatTest) {
213     hidl_vec<uint8_t> token(69);
214     for (size_t i = 0; i < 69; i++) {
215         token[i] = 0;
216     }
217 
218     Return<Status> ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
219     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(ret));
220 }
221 
222 // setFeature with an invalid HAT should fail.
TEST_F(FaceHidlTest,SetFeatureGarbageHatTest)223 TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) {
224     // Filling HAT with pseudorandom invalid data.
225     // Using default seed to make the test reproducible.
226     std::mt19937 gen(std::mt19937::default_seed);
227     std::uniform_int_distribution<uint8_t> dist;
228     hidl_vec<uint8_t> token(69);
229     for (size_t i = 0; i < 69; ++i) {
230         token[i] = dist(gen);
231     }
232 
233     Return<Status> ret = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token, 0);
234     ASSERT_EQ(Status::ILLEGAL_ARGUMENT, static_cast<Status>(ret));
235 }
236 
assertGetFeatureFails(const sp<IBiometricsFace> & service,uint32_t faceId,Feature feature)237 void assertGetFeatureFails(const sp<IBiometricsFace>& service, uint32_t faceId, Feature feature) {
238     // Features cannot be retrieved for invalid faces.
239     Return<void> res = service->getFeature(feature, faceId, [](const OptionalBool& result) {
240         ASSERT_EQ(Status::ILLEGAL_ARGUMENT, result.status);
241     });
242     ASSERT_TRUE(res.isOk());
243 }
244 
TEST_F(FaceHidlTest,GetFeatureRequireAttentionTest)245 TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) {
246     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_ATTENTION);
247 }
248 
TEST_F(FaceHidlTest,GetFeatureRequireDiversityTest)249 TEST_F(FaceHidlTest, GetFeatureRequireDiversityTest) {
250     assertGetFeatureFails(mService, 0 /* faceId */, Feature::REQUIRE_DIVERSITY);
251 }
252 
253 // revokeChallenge should always return within the timeout
TEST_F(FaceHidlTest,RevokeChallengeTest)254 TEST_F(FaceHidlTest, RevokeChallengeTest) {
255     auto start = std::chrono::system_clock::now();
256     Return<Status> ret = mService->revokeChallenge();
257     auto elapsed = std::chrono::system_clock::now() - start;
258     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
259     ASSERT_GE(kTimeout, elapsed);
260 }
261 
262 // The call to getAuthenticatorId should succeed.
TEST_F(FaceHidlTest,GetAuthenticatorIdTest)263 TEST_F(FaceHidlTest, GetAuthenticatorIdTest) {
264     Return<void> ret = mService->getAuthenticatorId(
265             [](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); });
266     ASSERT_TRUE(ret.isOk());
267 }
268 
269 // The call to enumerate should succeed.
TEST_F(FaceHidlTest,EnumerateTest)270 TEST_F(FaceHidlTest, EnumerateTest) {
271     Return<Status> ret = mService->enumerate();
272     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
273     auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
274     EXPECT_TRUE(res.no_timeout);
275 }
276 
277 // The call to remove should succeed for any faceId
TEST_F(FaceHidlTest,RemoveFaceTest)278 TEST_F(FaceHidlTest, RemoveFaceTest) {
279     // Remove a face
280     Return<Status> ret = mService->remove(kFaceId);
281     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
282 }
283 
284 // Remove should accept 0 to delete all faces
TEST_F(FaceHidlTest,RemoveAllFacesTest)285 TEST_F(FaceHidlTest, RemoveAllFacesTest) {
286     // Remove all faces
287     Return<Status> ret = mService->remove(0);
288     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
289 }
290 
291 // Active user should successfully set to a writable location.
TEST_F(FaceHidlTest,SetActiveUserTest)292 TEST_F(FaceHidlTest, SetActiveUserTest) {
293     // Create an active user
294     Return<Status> ret = mService->setActiveUser(2, kFacedataDir);
295     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
296 
297     // Reset active user
298     ret = mService->setActiveUser(kUserId, kFacedataDir);
299     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
300 }
301 
302 // Active user should fail to set to an unwritable location.
TEST_F(FaceHidlTest,SetActiveUserUnwritableTest)303 TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) {
304     // Create an active user to an unwritable location (device root dir)
305     Return<Status> ret = mService->setActiveUser(3, "/");
306     ASSERT_NE(Status::OK, static_cast<Status>(ret));
307 
308     // Reset active user
309     ret = mService->setActiveUser(kUserId, kFacedataDir);
310     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
311 }
312 
313 // Active user should fail to set to a null location.
TEST_F(FaceHidlTest,SetActiveUserNullTest)314 TEST_F(FaceHidlTest, SetActiveUserNullTest) {
315     // Create an active user to a null location.
316     Return<Status> ret = mService->setActiveUser(4, nullptr);
317     ASSERT_NE(Status::OK, static_cast<Status>(ret));
318 
319     // Reset active user
320     ret = mService->setActiveUser(kUserId, kFacedataDir);
321     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
322 }
323 
324 // Cancel should always return CANCELED from any starting state including
325 // the IDLE state.
TEST_F(FaceHidlTest,CancelTest)326 TEST_F(FaceHidlTest, CancelTest) {
327     Return<Status> ret = mService->cancel();
328     // check that we were able to make an IPC request successfully
329     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
330     auto res = mCallback->WaitForCallback(kCallbackNameOnError);
331     // make sure callback was invoked within kRevokeChallengeTimeout
332     EXPECT_TRUE(res.no_timeout);
333     EXPECT_EQ(FaceError::CANCELED, res.args->error);
334 }
335 
TEST_F(FaceHidlTest,OnLockoutChangedTest)336 TEST_F(FaceHidlTest, OnLockoutChangedTest) {
337     // Update active user and ensure onLockoutChanged was called.
338     Return<Status> ret = mService->setActiveUser(kUserId + 1, kFacedataDir);
339     ASSERT_EQ(Status::OK, static_cast<Status>(ret));
340 
341     // Make sure callback was invoked
342     auto res = mCallback->WaitForCallback(kCallbackNameOnLockoutChanged);
343     EXPECT_TRUE(res.no_timeout);
344 }
345 
346 }  // anonymous namespace
347 
main(int argc,char ** argv)348 int main(int argc, char** argv) {
349     ::testing::AddGlobalTestEnvironment(FaceHidlEnvironment::Instance());
350     ::testing::InitGoogleTest(&argc, argv);
351     FaceHidlEnvironment::Instance()->init(&argc, argv);
352     int status = RUN_ALL_TESTS();
353     LOG(INFO) << "Test result = " << status;
354     return status;
355 }
356