1 /*
2 * Copyright (C) 2017 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 "fingerprint_hidl_hal_test"
18
19 #include <VtsHalHidlTargetTestBase.h>
20 #include <VtsHalHidlTargetTestEnvBase.h>
21 #include <android-base/logging.h>
22 #include <android-base/properties.h>
23 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprint.h>
24 #include <android/hardware/biometrics/fingerprint/2.1/IBiometricsFingerprintClientCallback.h>
25 #include <hidl/HidlSupport.h>
26 #include <hidl/HidlTransportSupport.h>
27
28 #include <cinttypes>
29 #include <future>
30 #include <utility>
31
32 using android::base::GetUintProperty;
33 using android::Condition;
34 using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint;
35 using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
36 using android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
37 using android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
38 using android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
39 using android::hardware::hidl_vec;
40 using android::hardware::Return;
41 using android::Mutex;
42 using android::sp;
43
44 namespace {
45
46 static const uint32_t kTimeout = 3;
47 static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
48 static const uint32_t kGroupId = 99;
49 static std::string kTmpDir = "";
50 static const uint32_t kIterations = 1000;
51
52 // Wait for a callback to occur (signaled by the given future) up to the
53 // provided timeout. If the future is invalid or the callback does not come
54 // within the given time, returns false.
55 template<class ReturnType>
waitForCallback(std::future<ReturnType> future,std::chrono::milliseconds timeout=kTimeoutInSeconds)56 bool waitForCallback(
57 std::future<ReturnType> future,
58 std::chrono::milliseconds timeout = kTimeoutInSeconds) {
59 auto expiration = std::chrono::system_clock::now() + timeout;
60
61 EXPECT_TRUE(future.valid());
62 if (future.valid()) {
63 std::future_status status = future.wait_until(expiration);
64 EXPECT_NE(std::future_status::timeout, status)
65 << "Timed out waiting for callback";
66 if (status == std::future_status::ready) {
67 return true;
68 }
69 }
70
71 return false;
72 }
73
74 // Base callback implementation that just logs all callbacks by default
75 class FingerprintCallbackBase : public IBiometricsFingerprintClientCallback {
76 public:
77 // implement methods of IBiometricsFingerprintClientCallback
onEnrollResult(uint64_t,uint32_t,uint32_t,uint32_t)78 virtual Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t)
79 override {
80 ALOGD("Enroll callback called.");
81 return Return<void>();
82 }
83
onAcquired(uint64_t,FingerprintAcquiredInfo,int32_t)84 virtual Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t)
85 override {
86 ALOGD("Acquired callback called.");
87 return Return<void>();
88 }
89
onAuthenticated(uint64_t,uint32_t,uint32_t,const hidl_vec<uint8_t> &)90 virtual Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t,
91 const hidl_vec<uint8_t>&) override {
92 ALOGD("Authenticated callback called.");
93 return Return<void>();
94 }
95
onError(uint64_t,FingerprintError,int32_t)96 virtual Return<void> onError(uint64_t, FingerprintError, int32_t)
97 override {
98 ALOGD("Error callback called.");
99 EXPECT_TRUE(false); // fail any test that triggers an error
100 return Return<void>();
101 }
102
onRemoved(uint64_t,uint32_t,uint32_t,uint32_t)103 virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t)
104 override {
105 ALOGD("Removed callback called.");
106 return Return<void>();
107 }
108
onEnumerate(uint64_t,uint32_t,uint32_t,uint32_t)109 virtual Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t)
110 override {
111 ALOGD("Enumerate callback called.");
112 return Return<void>();
113 }
114 };
115
116 class EnumerateCallback : public FingerprintCallbackBase {
117 public:
onEnumerate(uint64_t deviceId,uint32_t fingerId,uint32_t groupId,uint32_t remaining)118 virtual Return<void> onEnumerate(uint64_t deviceId, uint32_t fingerId,
119 uint32_t groupId, uint32_t remaining) override {
120 this->deviceId = deviceId;
121 this->fingerId = fingerId;
122 this->groupId = groupId;
123 this->remaining = remaining;
124
125 if(remaining == 0UL) {
126 promise.set_value();
127 }
128 return Return<void>();
129 }
130
131 uint64_t deviceId;
132 uint32_t fingerId;
133 uint32_t groupId;
134 uint32_t remaining;
135 std::promise<void> promise;
136 };
137
138 class ErrorCallback : public FingerprintCallbackBase {
139 public:
ErrorCallback(bool filterErrors=false,FingerprintError errorType=FingerprintError::ERROR_NO_ERROR)140 ErrorCallback(
141 bool filterErrors=false,
142 FingerprintError errorType=FingerprintError::ERROR_NO_ERROR) {
143 this->filterErrors = filterErrors;
144 this->errorType = errorType;
145 }
146
onError(uint64_t deviceId,FingerprintError error,int32_t vendorCode)147 virtual Return<void> onError(uint64_t deviceId, FingerprintError error,
148 int32_t vendorCode) override {
149 if ((this->filterErrors && this->errorType == error) || !this->filterErrors) {
150 this->deviceId = deviceId;
151 this->error = error;
152 this->vendorCode = vendorCode;
153 promise.set_value();
154 }
155 return Return<void>();
156 }
157
158 bool filterErrors;
159 FingerprintError errorType;
160 uint64_t deviceId;
161 FingerprintError error;
162 int32_t vendorCode;
163 std::promise<void> promise;
164 };
165
166 class RemoveCallback : public FingerprintCallbackBase {
167 public:
RemoveCallback(uint32_t groupId)168 RemoveCallback(uint32_t groupId) {
169 this->removeGroupId = groupId;
170 }
171
onRemoved(uint64_t,uint32_t,uint32_t groupId,uint32_t remaining)172 virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t groupId,
173 uint32_t remaining) override {
174 EXPECT_EQ(this->removeGroupId, groupId);
175 if(remaining == 0UL) {
176 promise.set_value();
177 }
178 return Return<void>();
179 }
180
181 uint32_t removeGroupId;
182 std::promise<void> promise;
183 };
184
185 // Test environment for Fingerprint HIDL HAL.
186 class FingerprintHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
187 public:
188 // get the test environment singleton
Instance()189 static FingerprintHidlEnvironment* Instance() {
190 static FingerprintHidlEnvironment* instance = new FingerprintHidlEnvironment;
191 return instance;
192 }
193
registerTestServices()194 virtual void registerTestServices() override { registerTestService<IBiometricsFingerprint>(); }
195 };
196
197 class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase {
198 public:
SetUp()199 virtual void SetUp() override {
200 mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(
201 FingerprintHidlEnvironment::Instance()->getServiceName<IBiometricsFingerprint>());
202 ASSERT_FALSE(mService == nullptr);
203
204 /*
205 * Devices shipped from now on will instead store
206 * fingerprint data under /data/vendor_de/<user-id>/fpdata.
207 * Support for /data/vendor_de and /data/vendor_ce has been added to vold.
208 */
209
210 uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
211 if (api_level == 0) {
212 api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
213 }
214 ASSERT_TRUE(api_level != 0);
215
216 // 27 is the API number for O-MR1
217 if (api_level <= 27) {
218 kTmpDir = "/data/system/users/0/fpdata/";
219 } else {
220 kTmpDir = "/data/vendor_de/0/fpdata/";
221 }
222
223 Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
224 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
225 }
226
TearDown()227 virtual void TearDown() override {}
228
229 sp<IBiometricsFingerprint> mService;
230 };
231
232
233 // The service should be reachable.
TEST_F(FingerprintHidlTest,ConnectTest)234 TEST_F(FingerprintHidlTest, ConnectTest) {
235 sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
236 Return<uint64_t> rc = mService->setNotify(cb);
237 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
238 }
239
240 // Starting the service with null callback should succeed.
TEST_F(FingerprintHidlTest,ConnectNullTest)241 TEST_F(FingerprintHidlTest, ConnectNullTest) {
242 Return<uint64_t> rc = mService->setNotify(NULL);
243 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
244 }
245
246 // Pre-enroll should always return unique, cryptographically secure, non-zero number
TEST_F(FingerprintHidlTest,PreEnrollTest)247 TEST_F(FingerprintHidlTest, PreEnrollTest) {
248 std::map<uint64_t, uint64_t> m;
249
250 for(unsigned int i = 0; i < kIterations; ++i) {
251 uint64_t res = static_cast<uint64_t>(mService->preEnroll());
252 EXPECT_NE(0UL, res);
253 m[res]++;
254 EXPECT_EQ(1UL, m[res]);
255 }
256 }
257
258 // Enroll with an invalid (all zeroes) HAT should fail.
TEST_F(FingerprintHidlTest,EnrollInvalidHatTest)259 TEST_F(FingerprintHidlTest, EnrollInvalidHatTest) {
260 sp<ErrorCallback> cb = new ErrorCallback();
261 Return<uint64_t> rc = mService->setNotify(cb);
262 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
263
264 uint8_t token[69];
265 for(int i=0; i<69; i++) {
266 token[i] = 0;
267 }
268
269 Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
270 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
271
272 // At least one call to onError should occur
273 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
274 ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
275 }
276
277 // Enroll with an invalid (null) HAT should fail.
TEST_F(FingerprintHidlTest,EnrollNullTest)278 TEST_F(FingerprintHidlTest, EnrollNullTest) {
279 sp<ErrorCallback> cb = new ErrorCallback();
280 Return<uint64_t> rc = mService->setNotify(cb);
281 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
282
283 uint8_t token[69];
284 Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout);
285 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
286
287 // At least one call to onError should occur
288 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
289 ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error);
290 }
291
292 // PostEnroll should always return within 3s
TEST_F(FingerprintHidlTest,PostEnrollTest)293 TEST_F(FingerprintHidlTest, PostEnrollTest) {
294 sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase();
295 Return<uint64_t> rc = mService->setNotify(cb);
296
297 auto start = std::chrono::system_clock::now();
298 Return<RequestStatus> res = mService->postEnroll();
299 auto elapsed = std::chrono::system_clock::now() - start;
300 ASSERT_GE(kTimeoutInSeconds, elapsed);
301 }
302
303 // getAuthenticatorId should always return non-zero numbers
TEST_F(FingerprintHidlTest,GetAuthenticatorIdTest)304 TEST_F(FingerprintHidlTest, GetAuthenticatorIdTest) {
305 Return<uint64_t> res = mService->getAuthenticatorId();
306 EXPECT_NE(0UL, static_cast<uint64_t>(res));
307 }
308
309 // Enumerate should always trigger onEnumerated(fid=0, rem=0) when there are no fingerprints
TEST_F(FingerprintHidlTest,EnumerateTest)310 TEST_F(FingerprintHidlTest, EnumerateTest) {
311 sp<EnumerateCallback> cb = new EnumerateCallback();
312 Return<uint64_t> rc = mService->setNotify(cb);
313 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
314
315 // Callback will return when rem=0 is found
316 Return<RequestStatus> res = mService->enumerate();
317 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
318 EXPECT_EQ(0UL, cb->fingerId);
319 EXPECT_EQ(0UL, cb->remaining);
320
321 }
322
323 // Remove should succeed on any inputs
324 // At least one callback with "remaining=0" should occur
TEST_F(FingerprintHidlTest,RemoveFingerprintTest)325 TEST_F(FingerprintHidlTest, RemoveFingerprintTest) {
326 // Register callback
327 sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
328 Return<uint64_t> rc = mService->setNotify(cb);
329 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
330
331 // Remove a fingerprint
332 Return<RequestStatus> res = mService->remove(kGroupId, 1);
333 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
334
335 // At least one call to onRemove with remaining=0 should occur
336 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
337 }
338
339 // Remove should accept 0 to delete all fingerprints
340 // At least one callback with "remaining=0" should occur.
TEST_F(FingerprintHidlTest,RemoveAllFingerprintsTest)341 TEST_F(FingerprintHidlTest, RemoveAllFingerprintsTest) {
342 // Register callback
343 sp<RemoveCallback> cb = new RemoveCallback(kGroupId);
344 Return<uint64_t> rc = mService->setNotify(cb);
345 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
346
347 // Remove all fingerprints
348 Return<RequestStatus> res = mService->remove(kGroupId, 0);
349 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
350 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
351 }
352
353 // Active group should successfully set to a writable location.
TEST_F(FingerprintHidlTest,SetActiveGroupTest)354 TEST_F(FingerprintHidlTest, SetActiveGroupTest) {
355 // Create an active group
356 Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir);
357 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
358
359 // Reset active group
360 res = mService->setActiveGroup(kGroupId, kTmpDir);
361 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
362 }
363
364 // Active group should fail to set to an unwritable location.
TEST_F(FingerprintHidlTest,SetActiveGroupUnwritableTest)365 TEST_F(FingerprintHidlTest, SetActiveGroupUnwritableTest) {
366 // Create an active group to an unwritable location (device root dir)
367 Return<RequestStatus> res = mService->setActiveGroup(3, "/");
368 ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
369
370 // Reset active group
371 res = mService->setActiveGroup(kGroupId, kTmpDir);
372 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
373 }
374
375 // Active group should fail to set to a null location.
TEST_F(FingerprintHidlTest,SetActiveGroupNullTest)376 TEST_F(FingerprintHidlTest, SetActiveGroupNullTest) {
377 // Create an active group to a null location.
378 Return<RequestStatus> res = mService->setActiveGroup(4, nullptr);
379 ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
380
381 // Reset active group
382 res = mService->setActiveGroup(kGroupId, kTmpDir);
383 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
384 }
385
386 // Cancel should always return ERROR_CANCELED from any starting state including
387 // the IDLE state.
TEST_F(FingerprintHidlTest,CancelTest)388 TEST_F(FingerprintHidlTest, CancelTest) {
389 sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
390 Return<uint64_t> rc = mService->setNotify(cb);
391 ASSERT_NE(0UL, static_cast<uint64_t>(rc));
392
393 Return<RequestStatus> res = mService->cancel();
394 // check that we were able to make an IPC request successfully
395 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
396
397 // make sure callback was invoked within kTimeoutInSeconds
398 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
399 // check error should be ERROR_CANCELED
400 ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
401 }
402
403 // A call to cancel should succeed during enroll.
TEST_F(FingerprintHidlTest,CancelEnrollTest)404 TEST_F(FingerprintHidlTest, CancelEnrollTest) {
405 Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir);
406 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
407
408 sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
409 Return<uint64_t> rc = mService->setNotify(cb);
410 ASSERT_NE(0U, static_cast<uint64_t>(rc));
411
412 uint8_t token[69];
413 res = mService->enroll(token, kGroupId, kTimeout);
414 // check that we were able to make an IPC request successfully
415 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
416
417 res = mService->cancel();
418 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
419
420 // make sure callback was invoked within kTimeoutInSeconds
421 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
422
423 // check error should be ERROR_CANCELED
424 ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
425 }
426
427 // A call to cancel should succeed during authentication.
TEST_F(FingerprintHidlTest,CancelAuthTest)428 TEST_F(FingerprintHidlTest, CancelAuthTest) {
429 sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
430 Return<uint64_t> rc = mService->setNotify(cb);
431 ASSERT_NE(0U, static_cast<uint64_t>(rc));
432
433 Return<RequestStatus> res = mService->authenticate(0, kGroupId);
434 // check that we were able to make an IPC request successfully
435 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
436
437 res = mService->cancel();
438 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
439
440 // make sure callback was invoked within kTimeoutInSeconds
441 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
442
443 // check error should be ERROR_CANCELED
444 ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
445 }
446
447 // A call to cancel should succeed during authentication.
TEST_F(FingerprintHidlTest,CancelRemoveTest)448 TEST_F(FingerprintHidlTest, CancelRemoveTest) {
449 sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
450 Return<uint64_t> rc = mService->setNotify(cb);
451 ASSERT_NE(0U, static_cast<uint64_t>(rc));
452
453 // Remove a fingerprint
454 Return<RequestStatus> res = mService->remove(kGroupId, 1);
455 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
456
457 res = mService->cancel();
458 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
459
460 // make sure callback was invoked within kTimeoutInSeconds
461 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
462
463 // check error should be ERROR_CANCELED
464 ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
465 }
466
467 // A call to cancel should succeed during authentication.
TEST_F(FingerprintHidlTest,CancelRemoveAllTest)468 TEST_F(FingerprintHidlTest, CancelRemoveAllTest) {
469 sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED);
470 Return<uint64_t> rc = mService->setNotify(cb);
471 ASSERT_NE(0U, static_cast<uint64_t>(rc));
472
473 // Remove a fingerprint
474 Return<RequestStatus> res = mService->remove(kGroupId, 0);
475 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
476
477 res = mService->cancel();
478 ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res));
479
480 // make sure callback was invoked within kTimeoutInSeconds
481 ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
482
483 // check error should be ERROR_CANCELED
484 ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error);
485 }
486 } // anonymous namespace
487
main(int argc,char ** argv)488 int main(int argc, char **argv) {
489 ::testing::AddGlobalTestEnvironment(FingerprintHidlEnvironment::Instance());
490 ::testing::InitGoogleTest(&argc, argv);
491 FingerprintHidlEnvironment::Instance()->init(&argc, argv);
492 int status = RUN_ALL_TESTS();
493 LOG(INFO) << "Test result = " << status;
494 return status;
495 }
496
497