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