diff --git a/biometrics/face/1.1/vts/functional/Android.bp b/biometrics/face/1.1/vts/functional/Android.bp new file mode 100644 index 0000000000..ccbb3994e1 --- /dev/null +++ b/biometrics/face/1.1/vts/functional/Android.bp @@ -0,0 +1,29 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +cc_test { + name: "VtsHalBiometricsFaceV1_1TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: ["VtsHalBiometricsFaceV1_1TargetTest.cpp"], + static_libs: [ + "android.hardware.biometrics.face@1.0", + "android.hardware.biometrics.face@1.1", + ], + test_suites: [ + "general-tests", + "vts-core", + ], +} diff --git a/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp new file mode 100644 index 0000000000..c2431c6727 --- /dev/null +++ b/biometrics/face/1.1/vts/functional/VtsHalBiometricsFaceV1_1TargetTest.cpp @@ -0,0 +1,163 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "biometrics_face_hidl_hal_test" + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +using android::sp; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo; +using android::hardware::biometrics::face::V1_0::FaceError; +using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback; +using android::hardware::biometrics::face::V1_0::OptionalUint64; +using android::hardware::biometrics::face::V1_0::Status; +using android::hardware::biometrics::face::V1_1::IBiometricsFace; + +namespace { + +// Arbitrary, nonexistent userId +constexpr uint32_t kUserId = 9; +constexpr uint32_t kTimeoutSec = 3; +constexpr auto kTimeout = std::chrono::seconds(kTimeoutSec); +constexpr char kFacedataDir[] = "/data/vendor_de/0/facedata"; +constexpr char kCallbackNameOnError[] = "onError"; + +// Callback arguments that need to be captured for the tests. +struct FaceCallbackArgs { + // The error passed to the last onError() callback. + FaceError error; + + // The userId passed to the last callback. + int32_t userId; +}; + +// Test callback class for the BiometricsFace HAL. +// The HAL will call these callback methods to notify about completed operations +// or encountered errors. +class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase, + public IBiometricsFaceClientCallback { + public: + Return onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override { return Void(); } + + Return onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec&) override { + return Void(); + } + + Return onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override { + return Void(); + } + + Return onError(uint64_t, int32_t userId, FaceError error, int32_t) override { + FaceCallbackArgs args = {}; + args.error = error; + args.userId = userId; + NotifyFromCallback(kCallbackNameOnError, args); + return Void(); + } + + Return onRemoved(uint64_t, const hidl_vec&, int32_t) override { return Void(); } + + Return onEnumerate(uint64_t, const hidl_vec&, int32_t) override { + return Void(); + } + + Return onLockoutChanged(uint64_t) override { return Void(); } +}; + +// Test class for the BiometricsFace HAL. +class FaceHidlTest : public ::testing::TestWithParam { + public: + void SetUp() override { + mService = IBiometricsFace::getService(GetParam()); + ASSERT_NE(mService, nullptr); + mCallback = new FaceCallback(); + mCallback->SetWaitTimeoutDefault(kTimeout); + Return ret1 = mService->setCallback(mCallback, [](const OptionalUint64& res) { + ASSERT_EQ(Status::OK, res.status); + // Makes sure the "deviceId" represented by "res.value" is not 0. + // 0 would mean the HIDL is not available. + ASSERT_NE(0UL, res.value); + }); + ASSERT_TRUE(ret1.isOk()); + Return ret2 = mService->setActiveUser(kUserId, kFacedataDir); + ASSERT_EQ(Status::OK, static_cast(ret2)); + } + + void TearDown() override {} + + sp mService; + sp mCallback; +}; + +// enroll with an invalid (all zeroes) HAT should fail. +TEST_P(FaceHidlTest, EnrollRemotelyZeroHatTest) { + // Filling HAT with zeros + hidl_vec token(69); + for (size_t i = 0; i < 69; i++) { + token[i] = 0; + } + + Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +// enroll with an invalid HAT should fail. +TEST_P(FaceHidlTest, EnrollRemotelyGarbageHatTest) { + // Filling HAT with pseudorandom invalid data. + // Using default seed to make the test reproducible. + std::mt19937 gen(std::mt19937::default_seed); + std::uniform_int_distribution dist; + hidl_vec token(69); + for (size_t i = 0; i < 69; ++i) { + token[i] = dist(gen); + } + + Return ret = mService->enrollRemotely(token, kTimeoutSec, {}); + ASSERT_EQ(Status::OK, static_cast(ret)); + + // onError should be called with a meaningful (nonzero) error. + auto res = mCallback->WaitForCallback(kCallbackNameOnError); + EXPECT_TRUE(res.no_timeout); + EXPECT_EQ(kUserId, res.args->userId); + EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error); +} + +} // anonymous namespace + +INSTANTIATE_TEST_SUITE_P( + PerInstance, FaceHidlTest, + testing::ValuesIn(android::hardware::getAllHalInstanceNames(IBiometricsFace::descriptor)), + android::hardware::PrintInstanceNameToString);