diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-03-28 04:17:46 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-03-28 04:17:46 +0000 |
commit | d809c4ba0095cedbeb3527e97baec214642059ed (patch) | |
tree | 2379f92f0e5eae5b26a7fd46d2c35ead7f610f5a | |
parent | 779d9f3519aabd5a22e5368ee5e2cd14ec952c59 (diff) | |
parent | dfe3d8186f6a17e06a34a7f2529a3caf25fdb648 (diff) | |
download | android_hardware_interfaces-d809c4ba0095cedbeb3527e97baec214642059ed.tar.gz android_hardware_interfaces-d809c4ba0095cedbeb3527e97baec214642059ed.tar.bz2 android_hardware_interfaces-d809c4ba0095cedbeb3527e97baec214642059ed.zip |
Merge "Fingerprint vts tests."
-rw-r--r-- | biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp | 519 |
1 files changed, 395 insertions, 124 deletions
diff --git a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp index cd38f2e6a..d3f66126d 100644 --- a/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp +++ b/biometrics/fingerprint/2.1/vts/functional/VtsHalBiometricsFingerprintV2_1TargetTest.cpp @@ -23,6 +23,10 @@ #include <hidl/HidlTransportSupport.h> #include <VtsHalHidlTargetTestBase.h> +#include <cinttypes> +#include <future> +#include <utility> + using android::Condition; using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprint; using android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback; @@ -34,156 +38,423 @@ using android::hardware::Return; using android::Mutex; using android::sp; -class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase { +namespace { + +static const uint32_t kTimeout = 3; +static const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout); +static const uint32_t kGroupId = 99; +static const std::string kTmpDir = "/data/local/tmp/"; +static const uint32_t kIterations = 1000; + +// Wait for a callback to occur (signaled by the given future) up to the +// provided timeout. If the future is invalid or the callback does not come +// within the given time, returns false. +template<class ReturnType> +bool waitForCallback( + std::future<ReturnType> future, + std::chrono::milliseconds timeout = kTimeoutInSeconds) { + auto expiration = std::chrono::system_clock::now() + timeout; + + EXPECT_TRUE(future.valid()); + if (future.valid()) { + std::future_status status = future.wait_until(expiration); + EXPECT_NE(std::future_status::timeout, status) + << "Timed out waiting for callback"; + if (status == std::future_status::ready) { + return true; + } + } + + return false; +} + +// Base callback implementation that just logs all callbacks by default +class FingerprintCallbackBase : public IBiometricsFingerprintClientCallback { + public: + // implement methods of IBiometricsFingerprintClientCallback + virtual Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, uint32_t) + override { + ALOGD("Enroll callback called."); + return Return<void>(); + } + + virtual Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, int32_t) + override { + ALOGD("Acquired callback called."); + return Return<void>(); + } + + virtual Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, + const hidl_vec<uint8_t>&) override { + ALOGD("Authenticated callback called."); + return Return<void>(); + } -protected: - class MyCallback : public IBiometricsFingerprintClientCallback { - - // implement methods of IBiometricsFingerprintClientCallback - virtual Return<void> onEnrollResult(uint64_t, uint32_t, uint32_t, - uint32_t) override { - callBackCalled(); - return Return<void>(); - } - - virtual Return<void> onAcquired(uint64_t, FingerprintAcquiredInfo, - int32_t) override { - callBackCalled(); - return Return<void>(); - } - - virtual Return<void> onAuthenticated(uint64_t, uint32_t, uint32_t, - const hidl_vec<uint8_t>&) override { - callBackCalled(); - return Return<void>(); - } - - virtual Return<void> onError(uint64_t, FingerprintError error, int32_t) - override { - mTestCase->mErr = error; - callBackCalled(); - return Return<void>(); - } - - virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) - override { - callBackCalled(); - return Return<void>(); - } - - virtual Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, - uint32_t) override { - callBackCalled(); - return Return<void>(); - } - - void callBackCalled () { - mTestCase->mCallbackCalled = true; - mTestCase->mCallbackCond.broadcast(); - } - - FingerprintHidlTest* mTestCase; - public: - MyCallback(FingerprintHidlTest* aTest) : mTestCase(aTest) {} - }; - - sp<MyCallback> mCallback; - bool mCallbackCalled; - Condition mCallbackCond; - FingerprintError mErr; - Mutex mLock; - sp<IBiometricsFingerprint> mService; - static const unsigned int kThresholdInSeconds = 3; - - void clearErr () { - mErr = FingerprintError::ERROR_NO_ERROR; + virtual Return<void> onError(uint64_t, FingerprintError, int32_t) + override { + ALOGD("Error callback called."); + EXPECT_TRUE(false); // fail any test that triggers an error + return Return<void>(); + } + + virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t, uint32_t) + override { + ALOGD("Removed callback called."); + return Return<void>(); + } + + virtual Return<void> onEnumerate(uint64_t, uint32_t, uint32_t, uint32_t) + override { + ALOGD("Enumerate callback called."); + return Return<void>(); + } +}; + +class EnumerateCallback : public FingerprintCallbackBase { + public: + virtual Return<void> onEnumerate(uint64_t deviceId, uint32_t fingerId, + uint32_t groupId, uint32_t remaining) override { + this->deviceId = deviceId; + this->fingerId = fingerId; + this->groupId = groupId; + this->remaining = remaining; + + if(remaining == 0UL) { + promise.set_value(); } + return Return<void>(); + } - // Timed callback mechanism. Will block up to kThresholdInSeconds, - // returning true if callback was invoked in that time frame. - bool waitForCallback(const unsigned int seconds = kThresholdInSeconds) { - nsecs_t reltime = seconds_to_nanoseconds(seconds); - Mutex::Autolock _l(mLock); - nsecs_t endTime = systemTime() + reltime; - while (!mCallbackCalled) { - if (reltime == 0) { - mCallbackCond.wait(mLock); - } else { - nsecs_t now = systemTime(); - if (now > endTime) { - return false; - } - mCallbackCond.waitRelative(mLock, endTime - now); - } - } - return true; + uint64_t deviceId; + uint32_t fingerId; + uint32_t groupId; + uint32_t remaining; + std::promise<void> promise; +}; + +class ErrorCallback : public FingerprintCallbackBase { + public: + ErrorCallback( + bool filterErrors=false, + FingerprintError errorType=FingerprintError::ERROR_NO_ERROR) { + this->filterErrors = filterErrors; + this->errorType = errorType; + } + + virtual Return<void> onError(uint64_t deviceId, FingerprintError error, + int32_t vendorCode) override { + if ((this->filterErrors && this->errorType == error) || !this->filterErrors) { + this->deviceId = deviceId; + this->error = error; + this->vendorCode = vendorCode; + promise.set_value(); } -public: - FingerprintHidlTest (): mCallbackCalled(false) {} + return Return<void>(); + } - virtual void SetUp() override { - mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(); + bool filterErrors; + FingerprintError errorType; + uint64_t deviceId; + FingerprintError error; + int32_t vendorCode; + std::promise<void> promise; +}; - ASSERT_NE(mService, nullptr); - clearErr(); +class RemoveCallback : public FingerprintCallbackBase { + public: + RemoveCallback(uint32_t groupId) { + this->removeGroupId = groupId; + } - mCallback = new MyCallback(this); - // TODO: instantly fail any test that receives a death notification + virtual Return<void> onRemoved(uint64_t, uint32_t, uint32_t groupId, + uint32_t remaining) override { + EXPECT_EQ(this->removeGroupId, groupId); + if(remaining == 0UL) { + promise.set_value(); } + return Return<void>(); + } - virtual void TearDown() override {} + uint32_t removeGroupId; + std::promise<void> promise; }; -class FingerprintHidlEnvironment : public ::testing::Environment { -public: - virtual void SetUp() {} - virtual void TearDown() {} +class FingerprintHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + virtual void SetUp() override { + mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFingerprint>(); + ASSERT_FALSE(mService == nullptr); + + // Create an active group + Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + } + + virtual void TearDown() override {} + + sp<IBiometricsFingerprint> mService; }; + // The service should be reachable. TEST_F(FingerprintHidlTest, ConnectTest) { - Return<uint64_t> rc = mService->setNotify(mCallback); - EXPECT_NE(rc, 0UL); + sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase(); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); +} + +// Starting the service with null callback should succeed. +TEST_F(FingerprintHidlTest, ConnectNullTest) { + Return<uint64_t> rc = mService->setNotify(NULL); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); +} + +// Pre-enroll should always return unique, cryptographically secure, non-zero number +TEST_F(FingerprintHidlTest, PreEnrollTest) { + std::map<uint64_t, uint64_t> m; + + for(unsigned int i = 0; i < kIterations; ++i) { + uint64_t res = static_cast<uint64_t>(mService->preEnroll()); + EXPECT_NE(0UL, res); + m[res]++; + EXPECT_EQ(1UL, m[res]); + } +} + +// Enroll with an invalid (all zeroes) HAT should fail. +TEST_F(FingerprintHidlTest, EnrollInvalidHatTest) { + sp<ErrorCallback> cb = new ErrorCallback(); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); + + uint8_t token[69]; + for(int i=0; i<69; i++) { + token[i] = 0; + } + + Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // At least one call to onError should occur + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error); +} + +// Enroll with an invalid (null) HAT should fail. +TEST_F(FingerprintHidlTest, EnrollNullTest) { + sp<ErrorCallback> cb = new ErrorCallback(); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); + + uint8_t token[69]; + Return<RequestStatus> res = mService->enroll(token, kGroupId, kTimeout); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // At least one call to onError should occur + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + ASSERT_NE(FingerprintError::ERROR_NO_ERROR, cb->error); +} + +// PostEnroll should always return within 3s +TEST_F(FingerprintHidlTest, PostEnrollTest) { + sp<FingerprintCallbackBase> cb = new FingerprintCallbackBase(); + Return<uint64_t> rc = mService->setNotify(cb); + + auto start = std::chrono::system_clock::now(); + Return<RequestStatus> res = mService->postEnroll(); + auto elapsed = std::chrono::system_clock::now() - start; + ASSERT_GE(kTimeoutInSeconds, elapsed); +} + +// getAuthenticatorId should always return non-zero numbers +TEST_F(FingerprintHidlTest, GetAuthenticatorIdTest) { + Return<uint64_t> res = mService->getAuthenticatorId(); + EXPECT_NE(0UL, static_cast<uint64_t>(res)); +} + +// Enumerate should always trigger onEnumerated(fid=0, rem=0) when there are no fingerprints +TEST_F(FingerprintHidlTest, EnumerateTest) { + sp<EnumerateCallback> cb = new EnumerateCallback(); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); + + // Callback will return when rem=0 is found + Return<RequestStatus> res = mService->enumerate(); + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + EXPECT_EQ(0UL, cb->fingerId); + EXPECT_EQ(0UL, cb->remaining); + +} + +// Remove should succeed on any inputs +// At least one callback with "remaining=0" should occur +TEST_F(FingerprintHidlTest, RemoveFingerprintTest) { + // Register callback + sp<RemoveCallback> cb = new RemoveCallback(kGroupId); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); + + // Remove a fingerprint + Return<RequestStatus> res = mService->remove(kGroupId, 1); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // At least one call to onRemove with remaining=0 should occur + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); +} + +// Remove should accept 0 to delete all fingerprints +// At least one callback with "remaining=0" should occur. +TEST_F(FingerprintHidlTest, RemoveAllFingerprintsTest) { + // Register callback + sp<RemoveCallback> cb = new RemoveCallback(kGroupId); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); + + // Remove all fingerprints + Return<RequestStatus> res = mService->remove(kGroupId, 0); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); +} + +// Active group should successfully set to a writable location. +TEST_F(FingerprintHidlTest, SetActiveGroupTest) { + // Create an active group + Return<RequestStatus> res = mService->setActiveGroup(2, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // Reset active group + res = mService->setActiveGroup(kGroupId, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); +} + +// Active group should fail to set to an unwritable location. +TEST_F(FingerprintHidlTest, SetActiveGroupUnwritableTest) { + // Create an active group to an unwritable location (device root dir) + Return<RequestStatus> res = mService->setActiveGroup(3, "/"); + ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // Reset active group + res = mService->setActiveGroup(kGroupId, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); +} + +// Active group should fail to set to a null location. +TEST_F(FingerprintHidlTest, SetActiveGroupNullTest) { + // Create an active group to a null location. + Return<RequestStatus> res = mService->setActiveGroup(4, nullptr); + ASSERT_NE(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // Reset active group + res = mService->setActiveGroup(kGroupId, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); } // Cancel should always return ERROR_CANCELED from any starting state including // the IDLE state. TEST_F(FingerprintHidlTest, CancelTest) { - Return<uint64_t> rc = mService->setNotify(mCallback); - EXPECT_NE(rc, 0UL); + sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0UL, static_cast<uint64_t>(rc)); - Return<RequestStatus> res = mService->cancel(); - // make sure callback was invoked within kThresholdInSeconds - EXPECT_EQ(true, waitForCallback()); - // check that we were able to make an IPC request successfully - EXPECT_EQ(RequestStatus::SYS_OK, res); - // check error should be ERROR_CANCELED - EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr); + Return<RequestStatus> res = mService->cancel(); + // check that we were able to make an IPC request successfully + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // make sure callback was invoked within kTimeoutInSeconds + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + // check error should be ERROR_CANCELED + ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error); } -// A call to cancel should after any other method call should set the error -// state to canceled. -TEST_F(FingerprintHidlTest, AuthTest) { - Return<uint64_t> rc = mService->setNotify(mCallback); - EXPECT_NE(rc, 0UL); +// A call to cancel should succeed during enroll. +TEST_F(FingerprintHidlTest, CancelEnrollTest) { + Return<RequestStatus> res = mService->setActiveGroup(kGroupId, kTmpDir); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0U, static_cast<uint64_t>(rc)); - Return<RequestStatus> res = mService->authenticate(0, 0); - // check that we were able to make an IPC request successfully - EXPECT_EQ(RequestStatus::SYS_OK, res); + uint8_t token[69]; + res = mService->enroll(token, kGroupId, kTimeout); + // check that we were able to make an IPC request successfully + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); - res = mService->cancel(); - // make sure callback was invoked within kThresholdInSeconds - EXPECT_EQ(true, waitForCallback()); - // check that we were able to make an IPC request successfully - EXPECT_EQ(RequestStatus::SYS_OK, res); - // check error should be ERROR_CANCELED - EXPECT_EQ(FingerprintError::ERROR_CANCELED, mErr); + res = mService->cancel(); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // make sure callback was invoked within kTimeoutInSeconds + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + + // check error should be ERROR_CANCELED + ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error); } +// A call to cancel should succeed during authentication. +TEST_F(FingerprintHidlTest, CancelAuthTest) { + sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0U, static_cast<uint64_t>(rc)); + + Return<RequestStatus> res = mService->authenticate(0, kGroupId); + // check that we were able to make an IPC request successfully + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + res = mService->cancel(); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // make sure callback was invoked within kTimeoutInSeconds + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + + // check error should be ERROR_CANCELED + ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error); +} + +// A call to cancel should succeed during authentication. +TEST_F(FingerprintHidlTest, CancelRemoveTest) { + sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0U, static_cast<uint64_t>(rc)); + + // Remove a fingerprint + Return<RequestStatus> res = mService->remove(kGroupId, 1); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + res = mService->cancel(); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // make sure callback was invoked within kTimeoutInSeconds + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + + // check error should be ERROR_CANCELED + ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error); +} + +// A call to cancel should succeed during authentication. +TEST_F(FingerprintHidlTest, CancelRemoveAllTest) { + sp<ErrorCallback> cb = new ErrorCallback(true, FingerprintError::ERROR_CANCELED); + Return<uint64_t> rc = mService->setNotify(cb); + ASSERT_NE(0U, static_cast<uint64_t>(rc)); + + // Remove a fingerprint + Return<RequestStatus> res = mService->remove(kGroupId, 0); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + res = mService->cancel(); + ASSERT_EQ(RequestStatus::SYS_OK, static_cast<RequestStatus>(res)); + + // make sure callback was invoked within kTimeoutInSeconds + ASSERT_TRUE(waitForCallback(cb->promise.get_future())); + + // check error should be ERROR_CANCELED + ASSERT_EQ(FingerprintError::ERROR_CANCELED, cb->error); +} +} // anonymous namespace + int main(int argc, char **argv) { - ::testing::AddGlobalTestEnvironment(new FingerprintHidlEnvironment); - ::testing::InitGoogleTest(&argc, argv); - int status = RUN_ALL_TESTS(); - LOG(INFO) << "Test result = " << status; - return status; + ::testing::InitGoogleTest(&argc, argv); + int status = RUN_ALL_TESTS(); + LOG(INFO) << "Test result = " << status; + return status; } + |