summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTreeHugger Robot <treehugger-gerrit@google.com>2017-03-28 04:17:46 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-03-28 04:17:46 +0000
commitd809c4ba0095cedbeb3527e97baec214642059ed (patch)
tree2379f92f0e5eae5b26a7fd46d2c35ead7f610f5a
parent779d9f3519aabd5a22e5368ee5e2cd14ec952c59 (diff)
parentdfe3d8186f6a17e06a34a7f2529a3caf25fdb648 (diff)
downloadandroid_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.cpp519
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;
}
+