Merge "Implemented VTS tests for BiometricsFace.hal"
diff --git a/biometrics/face/1.0/vts/functional/Android.bp b/biometrics/face/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..fa68c4e
--- /dev/null
+++ b/biometrics/face/1.0/vts/functional/Android.bp
@@ -0,0 +1,24 @@
+//
+// Copyright (C) 2019 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_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalBiometricsFaceV1_0TargetTest.cpp"],
+    static_libs: ["android.hardware.biometrics.face@1.0"],
+    test_suites: ["general-tests"],
+}
+
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
new file mode 100644
index 0000000..f496bbe
--- /dev/null
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2019 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 "face_hidl_test"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFace.h>
+#include <android/hardware/biometrics/face/1.0/IBiometricsFaceClientCallback.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/HidlTransportSupport.h>
+#include <utils/Condition.h>
+
+#include <cinttypes>
+#include <cstdint>
+#include <future>
+#include <utility>
+
+using android::Condition;
+using android::Mutex;
+using android::sp;
+using android::base::GetUintProperty;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::biometrics::face::V1_0::FaceAcquiredInfo;
+using android::hardware::biometrics::face::V1_0::FaceError;
+using android::hardware::biometrics::face::V1_0::Feature;
+using android::hardware::biometrics::face::V1_0::IBiometricsFace;
+using android::hardware::biometrics::face::V1_0::IBiometricsFaceClientCallback;
+using android::hardware::biometrics::face::V1_0::OptionalUint64;
+using android::hardware::biometrics::face::V1_0::Status;
+
+namespace {
+
+const uint32_t kTimeout = 3;
+const std::chrono::seconds kTimeoutInSeconds = std::chrono::seconds(kTimeout);
+const uint32_t kUserId = 99;
+const uint32_t kFaceId = 5;
+const char kTmpDir[] = "/data/system/users/0/facedata";
+const int kIterations = 1000;
+
+const auto kAssertCallbackIsSet = [](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);
+};
+
+// 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 FaceCallbackBase : public IBiometricsFaceClientCallback {
+  public:
+    Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override {
+        ALOGD("Enroll callback called.");
+        return Return<void>();
+    }
+
+    Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
+        ALOGD("Authenticated callback called.");
+        return Return<void>();
+    }
+
+    Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
+        ALOGD("Acquired callback called.");
+        return Return<void>();
+    }
+
+    Return<void> onError(uint64_t, int32_t, FaceError, int32_t) override {
+        ALOGD("Error callback called.");
+        EXPECT_TRUE(false);  // fail any test that triggers an error
+        return Return<void>();
+    }
+
+    Return<void> onRemoved(uint64_t, uint32_t, int32_t, uint32_t) override {
+        ALOGD("Removed callback called.");
+        return Return<void>();
+    }
+
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t /* userId */) override {
+        ALOGD("Enumerate callback called.");
+        return Return<void>();
+    }
+
+    Return<void> onLockoutChanged(uint64_t) override {
+        ALOGD("LockoutChanged callback called.");
+        return Return<void>();
+    }
+};
+
+class EnumerateCallback : public FaceCallbackBase {
+  public:
+    Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
+        promise.set_value();
+        return Return<void>();
+    }
+
+    std::promise<void> promise;
+};
+
+class ErrorCallback : public FaceCallbackBase {
+  public:
+    ErrorCallback(bool filterErrors = false, FaceError errorType = FaceError::HW_UNAVAILABLE)
+        : filterErrors(filterErrors), errorType(errorType), hasError(false) {}
+
+    Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
+        if ((filterErrors && errorType == error) || !filterErrors) {
+            hasError = true;
+            this->error = error;
+            promise.set_value();
+        }
+        return Return<void>();
+    }
+
+    bool filterErrors;
+    FaceError errorType;
+    bool hasError;
+    FaceError error;
+    std::promise<void> promise;
+};
+
+class RemoveCallback : public FaceCallbackBase {
+  public:
+    explicit RemoveCallback(int32_t userId) : removeUserId(userId) {}
+
+    Return<void> onRemoved(uint64_t, uint32_t, int32_t userId, uint32_t remaining) override {
+        EXPECT_EQ(removeUserId, userId);
+        promise.set_value();
+        if (remaining == 0UL) {
+            promise.set_value();
+        }
+        return Return<void>();
+    }
+
+    int32_t removeUserId;
+    std::promise<void> promise;
+};
+
+// Test environment for Face HIDL HAL.
+class FaceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static FaceHidlEnvironment* Instance() {
+        static FaceHidlEnvironment* instance = new FaceHidlEnvironment;
+        return instance;
+    }
+
+    void registerTestServices() override { registerTestService<IBiometricsFace>(); }
+};
+
+class FaceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+  public:
+    void SetUp() override {
+        mService = ::testing::VtsHalHidlTargetTestBase::getService<IBiometricsFace>(
+                FaceHidlEnvironment::Instance()->getServiceName<IBiometricsFace>());
+        ASSERT_FALSE(mService == nullptr);
+        Return<Status> res = mService->setActiveUser(kUserId, kTmpDir);
+        ASSERT_EQ(Status::OK, static_cast<Status>(res));
+    }
+
+    void TearDown() override {}
+
+    sp<IBiometricsFace> mService;
+};
+
+// The service should be reachable.
+TEST_F(FaceHidlTest, ConnectTest) {
+    sp<FaceCallbackBase> cb = new FaceCallbackBase();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+}
+
+// Starting the service with null callback should succeed.
+TEST_F(FaceHidlTest, ConnectNullTest) {
+    mService->setCallback(nullptr, kAssertCallbackIsSet);
+}
+
+// generateChallenge should always return a unique, cryptographically secure,
+// non-zero number.
+TEST_F(FaceHidlTest, GenerateChallengeTest) {
+    std::map<uint64_t, int> m;
+    for (int i = 0; i < kIterations; ++i) {
+        mService->generateChallenge(kTimeout, [&m](const OptionalUint64& res) {
+            ASSERT_EQ(Status::OK, res.status);
+            EXPECT_NE(0UL, res.value);
+            m[res.value]++;
+            EXPECT_EQ(1UL, m[res.value]);
+        });
+    }
+}
+
+// enroll with an invalid (all zeroes) HAT should fail.
+TEST_F(FaceHidlTest, EnrollZeroHatTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    Return<Status> res = mService->enroll(token, kTimeout, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_TRUE(cb->hasError);
+}
+
+// enroll with an invalid HAT should fail.
+TEST_F(FaceHidlTest, EnrollGarbageHatTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    // Filling HAT with invalid data
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = i;
+    }
+
+    Return<Status> res = mService->enroll(token, kTimeout, {});
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_TRUE(cb->hasError);
+}
+
+// setFeature with an invalid (all zeros) HAT should fail.
+TEST_F(FaceHidlTest, SetFeatureZeroHatTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; i++) {
+        token[i] = 0;
+    }
+
+    Return<Status> res = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_TRUE(cb->hasError);
+}
+
+// setFeature with an invalid HAT should fail.
+TEST_F(FaceHidlTest, SetFeatureGarbageHatTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    // Filling HAT with invalid data
+    hidl_vec<uint8_t> token(69);
+    for (size_t i = 0; i < 69; ++i) {
+        token[i] = i;
+    }
+
+    Return<Status> res = mService->setFeature(Feature::REQUIRE_DIVERSITY, false, token);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // At least one call to onError should occur
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    ASSERT_TRUE(cb->hasError);
+}
+
+// getFeature by default should return true for REQUIRE_ATTENTION.
+TEST_F(FaceHidlTest, GetFeatureRequireAttentionTest) {
+    Return<bool> res = mService->getFeature(Feature::REQUIRE_ATTENTION);
+    ASSERT_EQ(true, static_cast<bool>(res));
+}
+
+// getFeature by default should return true for REQUIRE_DIVERSITY.
+TEST_F(FaceHidlTest, GetFeatureRequireDiversityTest) {
+    Return<bool> res = mService->getFeature(Feature::REQUIRE_DIVERSITY);
+    ASSERT_EQ(true, static_cast<bool>(res));
+}
+
+// revokeChallenge should always return within the timeout
+TEST_F(FaceHidlTest, RevokeChallengeTest) {
+    sp<FaceCallbackBase> cb = new FaceCallbackBase();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    auto start = std::chrono::system_clock::now();
+    mService->revokeChallenge();
+    auto elapsed = std::chrono::system_clock::now() - start;
+    ASSERT_GE(kTimeoutInSeconds, elapsed);
+}
+
+// The call to getAuthenticatorId should succeed.
+TEST_F(FaceHidlTest, GetAuthenticatorIdTest) {
+    mService->getAuthenticatorId(
+            [](const OptionalUint64& res) { ASSERT_EQ(Status::OK, res.status); });
+}
+
+// The call to enumerate should succeed.
+TEST_F(FaceHidlTest, EnumerateTest) {
+    sp<EnumerateCallback> cb = new EnumerateCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+    Return<Status> res = mService->enumerate();
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+}
+
+// The call to remove should succeed for any faceId
+TEST_F(FaceHidlTest, RemoveFaceTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    // Remove a face
+    Return<Status> res = mService->remove(kFaceId);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+}
+
+// Remove should accept 0 to delete all faces
+TEST_F(FaceHidlTest, RemoveAllFacesTest) {
+    sp<ErrorCallback> cb = new ErrorCallback();
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    // Remove all faces
+    Return<Status> res = mService->remove(0);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+}
+
+// Active user should successfully set to a writable location.
+TEST_F(FaceHidlTest, SetActiveUserTest) {
+    // Create an active user
+    Return<Status> res = mService->setActiveUser(2, kTmpDir);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // Reset active user
+    res = mService->setActiveUser(kUserId, kTmpDir);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+}
+
+// Active user should fail to set to an unwritable location.
+TEST_F(FaceHidlTest, SetActiveUserUnwritableTest) {
+    // Create an active user to an unwritable location (device root dir)
+    Return<Status> res = mService->setActiveUser(3, "/");
+    ASSERT_NE(Status::OK, static_cast<Status>(res));
+
+    // Reset active user
+    res = mService->setActiveUser(kUserId, kTmpDir);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+}
+
+// Active user should fail to set to a null location.
+TEST_F(FaceHidlTest, SetActiveUserNullTest) {
+    // Create an active user to a null location.
+    Return<Status> res = mService->setActiveUser(4, nullptr);
+    ASSERT_NE(Status::OK, static_cast<Status>(res));
+
+    // Reset active user
+    res = mService->setActiveUser(kUserId, kTmpDir);
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+}
+
+// Cancel should always return CANCELED from any starting state including
+// the IDLE state.
+TEST_F(FaceHidlTest, CancelTest) {
+    sp<ErrorCallback> cb = new ErrorCallback(true, FaceError::CANCELED);
+    mService->setCallback(cb, kAssertCallbackIsSet);
+
+    Return<Status> res = mService->cancel();
+    // check that we were able to make an IPC request successfully
+    ASSERT_EQ(Status::OK, static_cast<Status>(res));
+
+    // make sure callback was invoked within kTimeoutInSeconds
+    ASSERT_TRUE(waitForCallback(cb->promise.get_future()));
+    // check error should be CANCELED
+    ASSERT_EQ(FaceError::CANCELED, cb->error);
+}
+
+}  // anonymous namespace
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(FaceHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    FaceHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}