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