Support Face Virtual HAL operation latency randomization

Bug: 294254230
Test: atest android.hardware.biometrics.face.*
Change-Id: I1e0c2ba2f0f6756c79375b56c7d1a10f7f3bf5c4
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.cpp b/biometrics/face/aidl/default/FakeFaceEngine.cpp
index 7380611..bdc13fd 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.cpp
+++ b/biometrics/face/aidl/default/FakeFaceEngine.cpp
@@ -70,7 +70,7 @@
                                 EnrollmentType /*enrollmentType*/,
                                 const std::vector<Feature>& /*features*/,
                                 const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_start_enroll_latency().value_or(0));
+    BEGIN_OP(getLatency(FaceHalProperties::operation_enroll_latency()));
 
     // Do proper HAT verification in the real implementation.
     if (hat.mac.empty()) {
@@ -158,7 +158,7 @@
 
 void FakeFaceEngine::authenticateImpl(ISessionCallback* cb, int64_t /*operationId*/,
                                       const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_authenticate_latency().value_or(0));
+    BEGIN_OP(getLatency(FaceHalProperties::operation_authenticate_latency()));
 
     auto id = FaceHalProperties::enrollment_hit().value_or(0);
     auto enrolls = FaceHalProperties::enrollments();
@@ -291,7 +291,7 @@
 }
 
 void FakeFaceEngine::detectInteractionImpl(ISessionCallback* cb, const std::future<void>& cancel) {
-    BEGIN_OP(FaceHalProperties::operation_detect_interaction_latency().value_or(0));
+    BEGIN_OP(getLatency(FaceHalProperties::operation_detect_interaction_latency()));
 
     if (FaceHalProperties::operation_detect_interaction_fails().value_or(false)) {
         LOG(ERROR) << "Fail: operation_detect_interaction_fails";
@@ -418,4 +418,33 @@
     cb->onLockoutCleared();
 }
 
+int32_t FakeFaceEngine::getRandomInRange(int32_t bound1, int32_t bound2) {
+    std::uniform_int_distribution<int32_t> dist(std::min(bound1, bound2), std::max(bound1, bound2));
+    return dist(mRandom);
+}
+
+int32_t FakeFaceEngine::getLatency(const std::vector<std::optional<std::int32_t>>& latencyIn) {
+    int32_t res = DEFAULT_LATENCY;
+
+    std::vector<int32_t> latency;
+    for (auto x : latencyIn)
+        if (x.has_value()) latency.push_back(*x);
+
+    switch (latency.size()) {
+        case 0:
+            break;
+        case 1:
+            res = latency[0];
+            break;
+        case 2:
+            res = getRandomInRange(latency[0], latency[1]);
+            break;
+        default:
+            LOG(ERROR) << "ERROR: unexpected input of size " << latency.size();
+            break;
+    }
+
+    return res;
+}
+
 }  // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/FakeFaceEngine.h b/biometrics/face/aidl/default/FakeFaceEngine.h
index 8d9303c..b1e1388 100644
--- a/biometrics/face/aidl/default/FakeFaceEngine.h
+++ b/biometrics/face/aidl/default/FakeFaceEngine.h
@@ -60,6 +60,7 @@
     void getAuthenticatorIdImpl(ISessionCallback* cb);
     void invalidateAuthenticatorIdImpl(ISessionCallback* cb);
     void resetLockoutImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/);
+    int32_t getLatency(const std::vector<std::optional<std::int32_t>>& latencyVec);
 
     virtual std::string toString() const {
         std::ostringstream os;
@@ -71,6 +72,7 @@
     std::mt19937 mRandom;
 
   private:
+    int32_t getRandomInRange(int32_t bound1, int32_t bound2);
     static constexpr int32_t FACE_ACQUIRED_VENDOR_BASE = 1000;
     static constexpr int32_t FACE_ERROR_VENDOR_BASE = 1000;
     std::pair<AcquiredInfo, int32_t> convertAcquiredInfo(int32_t code);
diff --git a/biometrics/face/aidl/default/FakeLockoutTracker.h b/biometrics/face/aidl/default/FakeLockoutTracker.h
index f2d38f3..82cc313 100644
--- a/biometrics/face/aidl/default/FakeLockoutTracker.h
+++ b/biometrics/face/aidl/default/FakeLockoutTracker.h
@@ -28,7 +28,9 @@
   public:
     FakeLockoutTracker()
         : mFailedCount(0),
+          mTimedFailedCount(0),
           mLastFailedTime(0),
+          mCurrentMode(LockoutMode::kNone),
           mIsLockoutTimerStarted(false),
           mIsLockoutTimerAborted(false) {}
     ~FakeLockoutTracker() {}
diff --git a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
index 9548920..e69de29 100644
--- a/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
+++ b/biometrics/face/aidl/default/api/android.hardware.biometrics.face.VirtualProps-current.txt
@@ -1,98 +0,0 @@
-props {
-  owner: Vendor
-  module: "android.face.virt.FaceHalProperties"
-  prop {
-    api_name: "authenticator_id"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.authenticator_id"
-  }
-  prop {
-    api_name: "challenge"
-    type: Long
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.challenge"
-  }
-  prop {
-    api_name: "enrollment_hit"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.enrollment_hit"
-  }
-  prop {
-    api_name: "enrollments"
-    type: IntegerList
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.enrollments"
-  }
-  prop {
-    api_name: "features"
-    type: IntegerList
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.features"
-  }
-  prop {
-    api_name: "lockout"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.lockout"
-  }
-  prop {
-    api_name: "next_enrollment"
-    type: String
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.next_enrollment"
-  }
-  prop {
-    api_name: "operation_authenticate_duration"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_duration"
-  }
-  prop {
-    api_name: "operation_authenticate_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_fails"
-  }
-  prop {
-    api_name: "operation_authenticate_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_authenticate_latency"
-  }
-  prop {
-    api_name: "operation_detect_interaction_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
-  }
-  prop {
-    api_name: "operation_detect_interaction_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
-  }
-  prop {
-    api_name: "operation_enroll_fails"
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_enroll_fails"
-  }
-  prop {
-    api_name: "operation_start_enroll_latency"
-    type: Integer
-    access: ReadWrite
-    prop_name: "vendor.face.virtual.operation_start_enroll_latency"
-  }
-  prop {
-    api_name: "strength"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.strength"
-    enum_values: "convenience|weak|strong"
-  }
-  prop {
-    api_name: "type"
-    type: String
-    access: ReadWrite
-    prop_name: "persist.vendor.face.virtual.type"
-    enum_values: "IR|RGB"
-  }
-}
diff --git a/biometrics/face/aidl/default/face.sysprop b/biometrics/face/aidl/default/face.sysprop
index 95b0b43..997fd67 100644
--- a/biometrics/face/aidl/default/face.sysprop
+++ b/biometrics/face/aidl/default/face.sysprop
@@ -7,7 +7,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.type"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     enum_values: "IR|RGB"
     api_name: "type"
@@ -17,7 +17,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.strength"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     enum_values: "convenience|weak|strong"
     api_name: "strength"
@@ -27,7 +27,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.enrollments"
     type: IntegerList
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollments"
 }
@@ -36,7 +36,7 @@
 prop {
     prop_name: "persist.vendor.face.virtual.features"
     type: IntegerList
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "features"
 }
@@ -46,20 +46,11 @@
 prop {
     prop_name: "vendor.face.virtual.enrollment_hit"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "enrollment_hit"
 }
 
-# The initial latency for enrollment
-prop {
-    prop_name: "vendor.face.virtual.operation_start_enroll_latency"
-    type: Integer
-    scope: Public
-    access: ReadWrite
-    api_name: "operation_start_enroll_latency"
-}
-
 # the next enrollment in the format:
 # "<id>,<bucket_id>:<delay>:<succeeds>,<bucket_id>..."
 # for example: "0:1,0:100:1,1:200:1" indicating that bucket 0 took
@@ -69,7 +60,7 @@
 prop {
     prop_name: "vendor.face.virtual.next_enrollment"
     type: String
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "next_enrollment"
 }
@@ -78,7 +69,7 @@
 prop {
     prop_name: "vendor.face.virtual.authenticator_id"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "authenticator_id"
 }
@@ -87,7 +78,7 @@
 prop {
     prop_name: "vendor.face.virtual.challenge"
     type: Long
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "challenge"
 }
@@ -96,7 +87,7 @@
 prop {
     prop_name: "vendor.face.virtual.lockout"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "lockout"
 }
@@ -105,7 +96,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_fails"
 }
@@ -114,7 +105,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_detect_interaction_fails"
 }
@@ -123,7 +114,7 @@
 prop {
     prop_name: "vendor.face.virtual.operation_enroll_fails"
     type: Boolean
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_enroll_fails"
 }
@@ -133,8 +124,8 @@
 # the HAL will send AcquiredInfo::START and AcquiredInfo::FIRST_FRAME_RECEIVED
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_latency"
 }
@@ -142,18 +133,27 @@
 # add a latency to detectInteraction operations
 prop {
     prop_name: "vendor.face.virtual.operation_detect_interaction_latency"
-    type: Integer
-    scope: Public
+    type: IntegerList
+    scope: Internal
     access: ReadWrite
     api_name: "operation_detect_interaction_latency"
 }
 
+# add a latency to enroll operations
+prop {
+    prop_name: "vendor.face.virtual.operation_enroll_latency"
+    type: IntegerList
+    scope: Internal
+    access: ReadWrite
+    api_name: "operation_enroll_latency"
+}
+
 # millisecond duration for authenticate operations
 # (waits for changes to enrollment_hit)
 prop {
     prop_name: "vendor.face.virtual.operation_authenticate_duration"
     type: Integer
-    scope: Public
+    scope: Internal
     access: ReadWrite
     api_name: "operation_authenticate_duration"
 }
diff --git a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
index 69c9bf4..8c39b58 100644
--- a/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
+++ b/biometrics/face/aidl/default/tests/FakeFaceEngineTest.cpp
@@ -22,6 +22,7 @@
 #include <android-base/logging.h>
 
 #include "FakeFaceEngine.h"
+#include "util/Util.h"
 
 using namespace ::android::face::virt;
 using namespace ::aidl::android::hardware::biometrics::face;
@@ -137,11 +138,15 @@
     void SetUp() override {
         LOG(ERROR) << "JRM SETUP";
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
+    }
+
+    void TearDown() override {
         FaceHalProperties::enrollments({});
         FaceHalProperties::challenge({});
         FaceHalProperties::features({});
         FaceHalProperties::authenticator_id({});
         FaceHalProperties::strength("");
+        FaceHalProperties::operation_detect_interaction_latency({});
     }
 
     FakeFaceEngine mEngine;
@@ -383,4 +388,26 @@
     ASSERT_FALSE(mCallback->mAuthenticateFailed);
 }
 
+TEST_F(FakeFaceEngineTest, LatencyDefault) {
+    FaceHalProperties::operation_detect_interaction_latency({});
+    ASSERT_EQ(DEFAULT_LATENCY,
+              mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+}
+
+TEST_F(FakeFaceEngineTest, LatencyFixed) {
+    FaceHalProperties::operation_detect_interaction_latency({10});
+    ASSERT_EQ(10, mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency()));
+}
+
+TEST_F(FakeFaceEngineTest, LatencyRandom) {
+    FaceHalProperties::operation_detect_interaction_latency({1, 1000});
+    std::set<int32_t> latencySet;
+    for (int i = 0; i < 100; i++) {
+        auto x = mEngine.getLatency(FaceHalProperties::operation_detect_interaction_latency());
+        ASSERT_TRUE(x >= 1 && x <= 1000);
+        latencySet.insert(x);
+    }
+    ASSERT_TRUE(latencySet.size() > 95);  // unique values
+}
+
 }  // namespace aidl::android::hardware::biometrics::face