Refactor biometric virtual HAL config/control

for additional ways besides system property
Bug: 326227403
Test: atest android.hardware.biometrics.common.ConfigTest

Change-Id: Id0aa4961cc732c23f5da140eca81470316834b70
diff --git a/biometrics/common/config/Android.bp b/biometrics/common/config/Android.bp
new file mode 100644
index 0000000..d38ffe8
--- /dev/null
+++ b/biometrics/common/config/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2024 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_library {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "hardware_interfaces_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    name: "android.hardware.biometrics.common.config",
+    export_include_dirs: ["include"],
+    vendor: true,
+    srcs: [
+        "Config.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+    ],
+}
+
+cc_test_host {
+    name: "android.hardware.biometrics.common.ConfigTest",
+    local_include_dirs: ["include"],
+    srcs: [
+        "tests/ConfigTest.cpp",
+        "Config.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/biometrics/common/config/Config.cpp b/biometrics/common/config/Config.cpp
new file mode 100644
index 0000000..01ae864
--- /dev/null
+++ b/biometrics/common/config/Config.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2024 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 "VirtualHalConfig"
+
+#include "config/Config.h"
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include "../../util/include/util/Util.h"
+
+using ::android::base::ParseInt;
+
+namespace aidl::android::hardware::biometrics {
+
+Config::Config() : mSource(Config::ConfigSourceType::SOURCE_SYSPROP) {}
+
+ConfigValue Config::parseBool(const std::string& value) {
+    OptBool res;
+    if (value == "true")
+        res.emplace(true);
+    else if (value == "false")
+        res.emplace(false);
+    else
+        LOG(ERROR) << "ERROR: invalid bool " << value;
+    return res;
+}
+
+ConfigValue Config::parseString(const std::string& value) {
+    OptString res;
+    if (!value.empty()) res.emplace(value);
+    return res;
+}
+
+ConfigValue Config::parseInt32(const std::string& value) {
+    OptInt32 res;
+    if (!value.empty()) {
+        std::int32_t val;
+        if (ParseInt(value, &val)) res.emplace(val);
+    }
+    return res;
+}
+
+ConfigValue Config::parseInt64(const std::string& value) {
+    OptInt64 res;
+    if (!value.empty()) {
+        std::int64_t val = std::strtoull(value.c_str(), nullptr, 10);
+        if (val != 0LL or (val == 0LL && value == "0")) {
+            res.emplace(val);
+        }
+    }
+    return res;
+}
+
+ConfigValue Config::parseIntVec(const std::string& value) {
+    OptIntVec res;
+    for (auto& i : Util::parseIntSequence(value)) {
+        res.push_back(i);
+    }
+    return res;
+}
+
+void Config::init() {
+    LOG(INFO) << "calling init()";
+    int len = 0;
+    Config::Data* pd = getConfigData(&len);
+    for (int i = 0; i < len; i++) {
+        LOG(INFO) << "init():" << pd->name;
+        pd->value = (this->*(pd->parser))(pd->defaultValue);
+        setConfig(pd->name, *pd);
+        ++pd;
+    }
+}
+
+bool Config::setParam(const std::string& name, const std::string& value) {
+    auto it = mMap.find(name);
+    if (it == mMap.end()) {
+        LOG(ERROR) << "ERROR: setParam unknown config name " << name;
+        return false;
+    }
+    LOG(INFO) << "setParam name=" << name << "=" << value;
+
+    it->second.value = (this->*(it->second.parser))(value);
+
+    mSource = ConfigSourceType::SOURCE_AIDL;
+
+    return true;
+}
+
+ConfigValue Config::getInternal(const std::string& name) {
+    ConfigValue res;
+
+    auto data = mMap[name];
+    switch (mSource) {
+        case ConfigSourceType::SOURCE_SYSPROP:
+            res = data.getter();
+            break;
+        case ConfigSourceType::SOURCE_AIDL:
+            res = data.value;
+            break;
+        case ConfigSourceType::SOURCE_FILE:
+            LOG(WARNING) << "Unsupported";
+            break;
+        default:
+            LOG(ERROR) << " wrong srouce type " << (int)mSource;
+            break;
+    }
+
+    return res;
+}
+
+ConfigValue Config::getDefault(const std::string& name) {
+    return mMap[name].value;
+}
+
+bool Config::setInternal(const std::string& name, const ConfigValue& val) {
+    bool res = false;
+    auto data = mMap[name];
+
+    switch (mSource) {
+        case ConfigSourceType::SOURCE_SYSPROP:
+            res = data.setter(val);
+            break;
+        case ConfigSourceType::SOURCE_AIDL:
+            data.value = val;
+            res = true;
+            break;
+        case ConfigSourceType::SOURCE_FILE:
+            LOG(WARNING) << "Unsupported";
+            break;
+        default:
+            LOG(ERROR) << " wrong srouce type " << (int)mSource;
+            break;
+    }
+
+    return res;
+}
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/common/config/include/config/Config.h b/biometrics/common/config/include/config/Config.h
new file mode 100644
index 0000000..864e164
--- /dev/null
+++ b/biometrics/common/config/include/config/Config.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <cstdint>
+#include <iostream>
+#include <map>
+#include <optional>
+#include <sstream>
+#include <string>
+#include <variant>
+#include <vector>
+
+namespace aidl::android::hardware::biometrics {
+
+using OptBool = std::optional<bool>;
+using OptInt32 = std::optional<std::int32_t>;
+using OptInt64 = std::optional<std::int64_t>;
+using OptString = std::optional<std::string>;
+using OptIntVec = std::vector<std::optional<std::int32_t>>;
+
+using ConfigValue = std::variant<OptBool, OptInt32, OptInt64, OptString, OptIntVec>;
+
+class Config {
+  public:
+    struct Data {
+        std::string name;
+        ConfigValue (*getter)();
+        bool (*setter)(const ConfigValue&);
+        ConfigValue (Config::*parser)(const std::string&);
+        std::string defaultValue;
+        ConfigValue value;
+    };
+    enum class ConfigSourceType { SOURCE_SYSPROP, SOURCE_AIDL, SOURCE_FILE };
+
+  public:
+    Config();
+    virtual ~Config() = default;
+
+    template <typename T>
+    T get(const std::string& name) {
+        CHECK(mMap.count(name) > 0) << " biometric/config get invalid name: " << name;
+        std::optional<T> optval = std::get<std::optional<T>>(getInternal(name));
+        if (!optval) optval = std::get<std::optional<T>>(getDefault(name));
+        if (optval) return optval.value();
+        return T();
+    }
+    template <typename T>
+    bool set(const std::string& name, const T& val) {
+        CHECK(mMap.count(name) > 0) << " biometric/config set invalid name: " << name;
+        std::optional<T> aval(val);
+        ConfigValue cval(aval);
+        return setInternal(name, cval);
+    }
+    template <typename T>
+    T getopt(const std::string& name) {
+        CHECK(mMap.count(name) > 0) << " biometric/config get invalid name: " << name;
+        return std::get<T>(getInternal(name));
+    }
+    template <typename T>
+    bool setopt(const std::string& name, const T& val) {
+        CHECK(mMap.count(name) > 0) << " biometric/config set invalid name: " << name;
+        ConfigValue cval(val);
+        return setInternal(name, cval);
+    }
+
+    void init();
+
+    virtual Config::Data* getConfigData(int* size) = 0;
+    bool setParam(const std::string& name, const std::string& value);
+
+    ConfigValue parseBool(const std::string& value);
+    ConfigValue parseString(const std::string& name);
+    ConfigValue parseInt32(const std::string& value);
+    ConfigValue parseInt64(const std::string& value);
+    ConfigValue parseIntVec(const std::string& value);
+
+  protected:
+    void setConfig(const std::string& name, const Config::Data& value) { mMap[name] = value; }
+
+  private:
+    ConfigValue getInternal(const std::string& name);
+    bool setInternal(const std::string& name, const ConfigValue& val);
+    ConfigValue getDefault(const std::string& name);
+
+    Config::ConfigSourceType mSource;
+    std::map<std::string, Config::Data> mMap;
+};
+
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/common/config/tests/ConfigTest.cpp b/biometrics/common/config/tests/ConfigTest.cpp
new file mode 100644
index 0000000..d922040
--- /dev/null
+++ b/biometrics/common/config/tests/ConfigTest.cpp
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "config/Config.h"
+
+#define LOG_TAG "ConfigTest"
+#include <android-base/logging.h>
+
+// using namespace ::testing::Eq;
+using namespace testing;
+
+#define SP_DEFAULT_astring "astringSP"
+#define SP_DEFAULT_aint32 32
+#define SP_DEFAULT_aint64 64
+#define SP_DEFAULT_abool false
+#define SP_DEFAULT_avector \
+    { 1, 2, 3 }
+namespace aidl::android::hardware::biometrics {
+namespace TestHalProperties {
+OptString val_astring = SP_DEFAULT_astring;
+OptInt32 val_aint32 = SP_DEFAULT_aint32;
+OptInt64 val_aint64 = SP_DEFAULT_aint64;
+OptBool val_abool = SP_DEFAULT_abool;
+OptIntVec val_avector = SP_DEFAULT_avector;
+
+OptString astring() {
+    return val_astring;
+}
+bool astring(const OptString& v) {
+    val_astring = v;
+    return true;
+}
+OptInt32 aint32() {
+    return val_aint32;
+}
+bool aint32(const OptInt32& v) {
+    val_aint32 = v;
+    return true;
+}
+OptInt64 aint64() {
+    return val_aint64;
+}
+bool aint64(const OptInt64& v) {
+    val_aint64 = v;
+    return true;
+}
+OptBool abool() {
+    return val_abool;
+}
+bool abool(const OptBool& v) {
+    val_abool = v;
+    return true;
+}
+OptIntVec avector() {
+    return val_avector;
+}
+bool avector(const OptIntVec& v) {
+    val_avector = v;
+    return true;
+}
+}  // namespace TestHalProperties
+using namespace TestHalProperties;
+#define AIDL_DEFAULT_astring "astringAIDL"
+#define AIDL_DEFAULT_aint32 "320"
+#define AIDL_DEFAULT_aint64 "640"
+#define AIDL_DEFAULT_abool "true"
+#define AIDL_DEFAULT_avector "10,20,30"
+#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_)           \
+    ConfigValue _NAME_##Getter() {                          \
+        return TestHalProperties::_NAME_();                 \
+    }                                                       \
+    bool _NAME_##Setter(const ConfigValue& v) {             \
+        return TestHalProperties::_NAME_(std::get<_T_>(v)); \
+    }
+CREATE_GETTER_SETTER_WRAPPER(astring, OptString)
+CREATE_GETTER_SETTER_WRAPPER(aint32, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(aint64, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(abool, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(avector, std::vector<OptInt32>)
+
+// Name,Getter, Setter, Parser and default value
+#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
+static Config::Data configData[] = {
+        {NGS(astring), &Config::parseString, AIDL_DEFAULT_astring},
+        {NGS(aint32), &Config::parseInt32, AIDL_DEFAULT_aint32},
+        {NGS(aint64), &Config::parseInt64, AIDL_DEFAULT_aint64},
+        {NGS(abool), &Config::parseBool, AIDL_DEFAULT_abool},
+        {NGS(avector), &Config::parseIntVec, AIDL_DEFAULT_avector},
+};
+
+class TestConfig : public Config {
+    Config::Data* getConfigData(int* size) {
+        *size = sizeof(configData) / sizeof(configData[0]);
+        return configData;
+    }
+};
+
+class ConfigTest : public ::testing::Test {
+  protected:
+    void SetUp() override { cfg.init(); }
+    void TearDown() override {}
+
+    void switch2aidl() { cfg.setParam("astring", "astring"); }
+
+    TestConfig cfg;
+};
+
+TEST_F(ConfigTest, parseInt32) {
+    std::int32_t defval = 5678;
+    struct {
+        std::string strval;
+        std::int32_t expval;
+    } values[] = {
+            {"1234", 1234},
+            {"0", 0},
+            {"", defval},
+            {"xyz", defval},
+    };
+    for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+        ASSERT_EQ((std::get<OptInt32>(cfg.parseInt32(values[i].strval))).value_or(defval),
+                  values[i].expval);
+    }
+}
+
+TEST_F(ConfigTest, parseInt64) {
+    std::int64_t defval = 5678;
+    struct {
+        std::string strval;
+        std::int64_t expval;
+    } values[] = {
+            {"1234", 1234},  {"12345678909876", 12345678909876}, {"0", 0}, {"", defval},
+            {"xyz", defval},
+    };
+    for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+        ASSERT_EQ((std::get<OptInt64>(cfg.parseInt64(values[i].strval))).value_or(defval),
+                  values[i].expval);
+    }
+}
+
+TEST_F(ConfigTest, parseBool) {
+    bool defval = true;
+    struct {
+        std::string strval;
+        bool expval;
+    } values[] = {
+            {"false", false},
+            {"true", true},
+            {"", defval},
+            {"xyz", defval},
+    };
+    for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+        ASSERT_EQ((std::get<OptBool>(cfg.parseBool(values[i].strval))).value_or(defval),
+                  values[i].expval);
+    }
+}
+
+TEST_F(ConfigTest, parseIntVec) {
+    std::vector<std::optional<int>> defval = {};
+    struct {
+        std::string strval;
+        std::vector<std::optional<int>> expval;
+    } values[] = {
+            {"1", {1}}, {"1,2,3", {1, 2, 3}}, {"1,2,b", defval}, {"", defval}, {"xyz", defval},
+    };
+    for (int i = 0; i < sizeof(values) / sizeof(values[0]); i++) {
+        ASSERT_EQ(std::get<OptIntVec>(cfg.parseIntVec(values[i].strval)), values[i].expval);
+    }
+}
+
+TEST_F(ConfigTest, getters_sp) {
+    ASSERT_EQ(cfg.get<std::string>("astring"), val_astring);
+    ASSERT_EQ(cfg.get<std::int32_t>("aint32"), val_aint32);
+    ASSERT_EQ(cfg.get<std::int64_t>("aint64"), val_aint64);
+    ASSERT_EQ(cfg.get<bool>("abool"), val_abool);
+    OptIntVec exp{val_avector};
+    EXPECT_EQ(cfg.getopt<OptIntVec>("avector"), exp);
+}
+
+TEST_F(ConfigTest, setters_sp) {
+    std::string val_astring_new("astringNew");
+    ASSERT_TRUE(cfg.set<std::string>("astring", val_astring_new));
+    ASSERT_EQ(cfg.get<std::string>("astring"), val_astring_new);
+
+    std::int32_t val_aint32_new = val_aint32.value() + 100;
+    ASSERT_TRUE(cfg.set<std::int32_t>("aint32", val_aint32_new));
+    ASSERT_EQ(cfg.get<std::int32_t>("aint32"), val_aint32_new);
+
+    std::int64_t val_aint64_new = val_aint64.value() + 200;
+    ASSERT_TRUE(cfg.set<std::int64_t>("aint64", val_aint64_new));
+    ASSERT_EQ(cfg.get<std::int64_t>("aint64"), val_aint64_new);
+
+    bool val_abool_new = !val_abool.value();
+    ASSERT_TRUE(cfg.set<bool>("abool", val_abool_new));
+    ASSERT_EQ(cfg.get<bool>("abool"), val_abool_new);
+
+    OptIntVec val_avector_new{100, 200};
+    ASSERT_TRUE(cfg.setopt<OptIntVec>("avector", val_avector_new));
+    EXPECT_EQ(cfg.getopt<OptIntVec>("avector"), val_avector_new);
+}
+
+TEST_F(ConfigTest, setters_sp_null) {
+    val_astring = std::nullopt;
+    ASSERT_EQ(cfg.get<std::string>("astring"),
+              (std::get<OptString>(cfg.parseString(AIDL_DEFAULT_astring))).value());
+}
+
+TEST_F(ConfigTest, getters_aidl) {
+    cfg.setParam("astring", "astringAIDL");
+    ASSERT_EQ(cfg.get<std::string>("astring"),
+              (std::get<OptString>(cfg.parseString(AIDL_DEFAULT_astring))).value());
+    ASSERT_EQ(cfg.get<std::int32_t>("aint32"),
+              (std::get<OptInt32>(cfg.parseInt32(AIDL_DEFAULT_aint32))).value());
+    ASSERT_EQ(cfg.get<std::int64_t>("aint64"),
+              (std::get<OptInt64>(cfg.parseInt64(AIDL_DEFAULT_aint64))).value());
+    ASSERT_EQ(cfg.get<bool>("abool"),
+              (std::get<OptBool>(cfg.parseBool(AIDL_DEFAULT_abool))).value());
+    OptIntVec exp{std::get<OptIntVec>(cfg.parseIntVec(AIDL_DEFAULT_avector))};
+    EXPECT_EQ(cfg.getopt<OptIntVec>("avector"), exp);
+}
+
+TEST_F(ConfigTest, setters_aidl) {
+    std::string val_astring_new("astringNewAidl");
+    ASSERT_TRUE(cfg.set<std::string>("astring", val_astring_new));
+    ASSERT_EQ(cfg.get<std::string>("astring"), val_astring_new);
+
+    std::int32_t val_aint32_new = val_aint32.value() + 1000;
+    ASSERT_TRUE(cfg.set<std::int32_t>("aint32", val_aint32_new));
+    ASSERT_EQ(cfg.get<std::int32_t>("aint32"), val_aint32_new);
+
+    std::int64_t val_aint64_new = val_aint64.value() + 2000;
+    ASSERT_TRUE(cfg.set<std::int64_t>("aint64", val_aint64_new));
+    ASSERT_EQ(cfg.get<std::int64_t>("aint64"), val_aint64_new);
+
+    bool val_abool_new = !val_abool.value();
+    ASSERT_TRUE(cfg.set<bool>("abool", val_abool_new));
+    ASSERT_EQ(cfg.get<bool>("abool"), val_abool_new);
+
+    OptIntVec val_avector_new{1000, 2000};
+    ASSERT_TRUE(cfg.setopt<OptIntVec>("avector", val_avector_new));
+    EXPECT_EQ(cfg.getopt<OptIntVec>("avector"), val_avector_new);
+}
+
+TEST_F(ConfigTest, setParam) {
+    ASSERT_TRUE(cfg.setParam("aint32", "789"));
+    ASSERT_EQ(cfg.get<std::int32_t>("aint32"), 789);
+    ASSERT_TRUE(cfg.setParam("avector", "7,8,9,10"));
+    OptIntVec val_avector_new{7, 8, 9, 10};
+    EXPECT_EQ(cfg.getopt<OptIntVec>("avector"), val_avector_new);
+    ASSERT_FALSE(cfg.setParam("unknown", "any"));
+}
+}  // namespace aidl::android::hardware::biometrics
diff --git a/biometrics/common/util/include/util/Util.h b/biometrics/common/util/include/util/Util.h
index efd66bc..078669d 100644
--- a/biometrics/common/util/include/util/Util.h
+++ b/biometrics/common/util/include/util/Util.h
@@ -80,7 +80,9 @@
             if (ParseInt(seq, &val)) {
                 res.push_back(val);
             } else {
-                LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
+                if (!str.empty()) {
+                    LOG(WARNING) << "Invalid int sequence:" + str + " seq:" + seq;
+                }
                 res.clear();
                 break;
             }
diff --git a/biometrics/fingerprint/aidl/default/Android.bp b/biometrics/fingerprint/aidl/default/Android.bp
index c3ec4d0..501af07 100644
--- a/biometrics/fingerprint/aidl/default/Android.bp
+++ b/biometrics/fingerprint/aidl/default/Android.bp
@@ -20,6 +20,7 @@
         "FakeFingerprintEngineSide.cpp",
         "Fingerprint.cpp",
         "Session.cpp",
+        "FingerprintConfig.cpp",
         "main.cpp",
     ],
     stl: "c++_static",
@@ -34,9 +35,15 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.biometrics.common.thread",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.config",
         "android.hardware.keymaster-V4-ndk",
     ],
     installable: false, // install APEX instead
+    product_variables: {
+        debuggable: {
+            cflags: ["-DFPS_DEBUGGABLE"],
+        },
+    },
 }
 
 cc_test {
@@ -46,11 +53,11 @@
         "tests/FakeFingerprintEngineTest.cpp",
         "FakeFingerprintEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FingerprintConfig.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common.thread",
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
@@ -58,6 +65,8 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
     ],
     vendor: true,
     test_suites: ["general-tests"],
@@ -72,11 +81,11 @@
         "FakeFingerprintEngineUdfps.cpp",
         "FakeFingerprintEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FingerprintConfig.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common.thread",
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
@@ -84,6 +93,8 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.config",
+        "android.hardware.biometrics.common.thread",
     ],
     vendor: true,
     test_suites: ["general-tests"],
@@ -96,11 +107,11 @@
     srcs: [
         "tests/FakeLockoutTrackerTest.cpp",
         "FakeLockoutTracker.cpp",
+        "FingerprintConfig.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common.thread",
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
@@ -108,6 +119,8 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.config",
     ],
     vendor: true,
     test_suites: ["general-tests"],
@@ -122,11 +135,11 @@
         "Session.cpp",
         "FakeFingerprintEngine.cpp",
         "FakeLockoutTracker.cpp",
+        "FingerprintConfig.cpp",
     ],
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.biometrics.common.thread",
     ],
     static_libs: [
         "libandroid.hardware.biometrics.fingerprint.VirtualProps",
@@ -134,6 +147,8 @@
         "android.hardware.biometrics.common-V4-ndk",
         "android.hardware.keymaster-V4-ndk",
         "android.hardware.biometrics.common.util",
+        "android.hardware.biometrics.common.thread",
+        "android.hardware.biometrics.common.config",
     ],
     vendor: true,
     test_suites: ["general-tests"],
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index a7acf3d..8b8d046 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -40,13 +40,13 @@
     BEGIN_OP(0);
     std::uniform_int_distribution<int64_t> dist;
     auto challenge = dist(mRandom);
-    FingerprintHalProperties::challenge(challenge);
+    Fingerprint::cfg().set<std::int64_t>("challenge", challenge);
     cb->onChallengeGenerated(challenge);
 }
 
 void FakeFingerprintEngine::revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
     BEGIN_OP(0);
-    FingerprintHalProperties::challenge({});
+    Fingerprint::cfg().setopt<OptInt64>("challenge", std::nullopt);
     cb->onChallengeRevoked(challenge);
 }
 
@@ -81,8 +81,7 @@
                                                   const std::future<void>& cancel) {
     BEGIN_OP(0);
 
-    auto detectInteractionSupported =
-            FingerprintHalProperties::detect_interaction().value_or(false);
+    auto detectInteractionSupported = Fingerprint::cfg().get<bool>("detect_interaction");
     if (!detectInteractionSupported) {
         LOG(ERROR) << "Detect interaction is not supported";
         cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
@@ -131,10 +130,10 @@
 bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
                                                const keymaster::HardwareAuthToken&,
                                                const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
+    BEGIN_OP(getLatency(Fingerprint::cfg().getopt<OptIntVec>("operation_enroll_latency")));
 
     // Force error-out
-    auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
+    auto err = Fingerprint::cfg().get<std::int32_t>("operation_enroll_error");
     if (err != 0) {
         LOG(ERROR) << "Fail: operation_enroll_error";
         auto ec = convertError(err);
@@ -143,7 +142,7 @@
     }
 
     // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
-    auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
+    auto nextEnroll = Fingerprint::cfg().get<std::string>("next_enrollment");
     auto parts = Util::split(nextEnroll, ":");
     if (parts.size() != 3) {
         LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
@@ -172,19 +171,19 @@
 
         if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
             LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
-            FingerprintHalProperties::next_enrollment({});
+            Fingerprint::cfg().set<std::string>("next_enrollment", "");
             cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
         } else {  // progress and update props if last time
             LOG(INFO) << "onEnroll: " << enrollmentId << " left: " << left;
             if (left == 0) {
-                auto enrollments = FingerprintHalProperties::enrollments();
+                auto enrollments = Fingerprint::cfg().getopt<OptIntVec>("enrollments");
                 enrollments.emplace_back(enrollmentId);
-                FingerprintHalProperties::enrollments(enrollments);
-                FingerprintHalProperties::next_enrollment({});
+                Fingerprint::cfg().setopt<OptIntVec>("enrollments", enrollments);
+                Fingerprint::cfg().setopt<OptString>("next_enrollment", std::nullopt);
                 // change authenticatorId after new enrollment
-                auto id = FingerprintHalProperties::authenticator_id().value_or(0);
+                auto id = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
                 auto newId = id + 1;
-                FingerprintHalProperties::authenticator_id(newId);
+                Fingerprint::cfg().set<std::int64_t>("authenticator_id", newId);
                 LOG(INFO) << "Enrolled: " << enrollmentId;
             }
             cb->onEnrollmentProgress(enrollmentId, left);
@@ -197,11 +196,11 @@
 bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
                                                      int64_t /* operationId */,
                                                      const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
+    BEGIN_OP(getLatency(Fingerprint::cfg().getopt<OptIntVec>("operation_authenticate_latency")));
 
     int64_t now = Util::getSystemNanoTime();
-    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
-    auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
+    int64_t duration = Fingerprint::cfg().get<std::int32_t>("operation_authenticate_duration");
+    auto acquired = Fingerprint::cfg().get<std::string>("operation_authenticate_acquired");
     auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
 
@@ -218,14 +217,14 @@
 
     int i = 0;
     do {
-        if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
+        if (Fingerprint::cfg().get<bool>("operation_authenticate_fails")) {
             LOG(ERROR) << "Fail: operation_authenticate_fails";
             mLockoutTracker.addFailedAttempt();
             cb->onAuthenticationFailed();
             return false;
         }
 
-        auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
+        auto err = Fingerprint::cfg().get<std::int32_t>("operation_authenticate_error");
         if (err != 0) {
             LOG(ERROR) << "Fail: operation_authenticate_error";
             auto ec = convertError(err);
@@ -234,7 +233,7 @@
                             revisit if tests need*/
         }
 
-        if (FingerprintHalProperties::lockout().value_or(false)) {
+        if (Fingerprint::cfg().get<bool>("lockout")) {
             LOG(ERROR) << "Fail: lockout";
             cb->onLockoutPermanent();
             cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
@@ -256,8 +255,8 @@
         SLEEP_MS(duration / N);
     } while (!Util::hasElapsed(now, duration));
 
-    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
-    auto enrolls = FingerprintHalProperties::enrollments();
+    auto id = Fingerprint::cfg().get<std::int32_t>("enrollment_hit");
+    auto enrolls = Fingerprint::cfg().getopt<OptIntVec>("enrollments");
     auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
     if (id > 0 && isEnrolled) {
         cb->onAuthenticationSucceeded(id, {} /* hat */);
@@ -274,12 +273,13 @@
 
 bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
                                                        const std::future<void>& cancel) {
-    BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
+    BEGIN_OP(getLatency(
+            Fingerprint::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
 
-    int64_t duration =
-            FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
+    int32_t duration =
+            Fingerprint::cfg().get<std::int32_t>("operation_detect_interaction_duration");
 
-    auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
+    auto acquired = Fingerprint::cfg().get<std::string>("operation_detect_interaction_acquired");
     auto acquiredInfos = Util::parseIntSequence(acquired);
     int N = acquiredInfos.size();
     int64_t now = Util::getSystemNanoTime();
@@ -292,7 +292,7 @@
 
     int i = 0;
     do {
-        auto err = FingerprintHalProperties::operation_detect_interaction_error().value_or(0);
+        auto err = Fingerprint::cfg().get<std::int32_t>("operation_detect_interaction_error");
         if (err != 0) {
             LOG(ERROR) << "Fail: operation_detect_interaction_error";
             auto ec = convertError(err);
@@ -323,7 +323,7 @@
     BEGIN_OP(0);
 
     std::vector<int32_t> ids;
-    for (auto& enrollment : FingerprintHalProperties::enrollments()) {
+    for (auto& enrollment : Fingerprint::cfg().getopt<OptIntVec>("enrollments")) {
         auto id = enrollment.value_or(0);
         if (id > 0) {
             ids.push_back(id);
@@ -339,7 +339,7 @@
 
     std::vector<std::optional<int32_t>> newEnrollments;
     std::vector<int32_t> removed;
-    for (auto& enrollment : FingerprintHalProperties::enrollments()) {
+    for (auto& enrollment : Fingerprint::cfg().getopt<OptIntVec>("enrollments")) {
         auto id = enrollment.value_or(0);
         if (std::find(enrollmentIds.begin(), enrollmentIds.end(), id) != enrollmentIds.end()) {
             removed.push_back(id);
@@ -347,7 +347,7 @@
             newEnrollments.emplace_back(id);
         }
     }
-    FingerprintHalProperties::enrollments(newEnrollments);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", newEnrollments);
 
     cb->onEnrollmentsRemoved(enrollmentIds);
 }
@@ -355,10 +355,10 @@
 void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
     int64_t authenticatorId;
-    if (FingerprintHalProperties::enrollments().size() == 0) {
+    if (Fingerprint::cfg().getopt<OptIntVec>("enrollments").size() == 0) {
         authenticatorId = 0;
     } else {
-        authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
+        authenticatorId = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
         if (authenticatorId == 0) authenticatorId = 1;
     }
     cb->onAuthenticatorIdRetrieved(authenticatorId);
@@ -367,13 +367,13 @@
 void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
     BEGIN_OP(0);
     int64_t newId;
-    if (FingerprintHalProperties::enrollments().size() == 0) {
+    if (Fingerprint::cfg().getopt<OptIntVec>("enrollments").size() == 0) {
         newId = 0;
     } else {
-        auto id = FingerprintHalProperties::authenticator_id().value_or(0);
+        auto id = Fingerprint::cfg().get<std::int64_t>("authenticator_id");
         newId = id + 1;
     }
-    FingerprintHalProperties::authenticator_id(newId);
+    Fingerprint::cfg().set<std::int64_t>("authenticator_id", newId);
     cb->onAuthenticatorIdInvalidated(newId);
 }
 
@@ -390,7 +390,7 @@
 }
 
 void FakeFingerprintEngine::clearLockout(ISessionCallback* cb) {
-    FingerprintHalProperties::lockout(false);
+    Fingerprint::cfg().set<bool>("lockout", false);
     cb->onLockoutCleared();
     mLockoutTracker.reset();
 }
@@ -415,7 +415,7 @@
 }
 
 bool FakeFingerprintEngine::getSensorLocationConfig(SensorLocation& out) {
-    auto loc = FingerprintHalProperties::sensor_location().value_or("");
+    auto loc = Fingerprint::cfg().get<std::string>("sensor_location");
     auto isValidStr = false;
     auto dim = Util::split(loc, ":");
 
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
index 68b0f0d..496b5e3 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngineUdfps.cpp
@@ -20,6 +20,7 @@
 
 #include <fingerprint.sysprop.h>
 
+#include "Fingerprint.h"
 #include "util/CancellationSignal.h"
 #include "util/Util.h"
 
@@ -45,7 +46,7 @@
     BEGIN_OP(0);
     // verify whetehr touch coordinates/area matching sensor location ?
     mPointerDownTime = Util::getSystemNanoTime();
-    if (FingerprintHalProperties::control_illumination().value_or(false)) {
+    if (Fingerprint::cfg().get<bool>("control_illumination")) {
         fingerDownAction();
     }
     return ndk::ScopedAStatus::ok();
diff --git a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
index b0163ee..a056db5 100644
--- a/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeLockoutTracker.cpp
@@ -16,6 +16,7 @@
 
 #include "FakeLockoutTracker.h"
 #include <fingerprint.sysprop.h>
+#include "Fingerprint.h"
 #include "util/Util.h"
 
 using namespace ::android::fingerprint::virt;
@@ -29,16 +30,16 @@
 }
 
 void FakeLockoutTracker::addFailedAttempt() {
-    bool enabled = FingerprintHalProperties::lockout_enable().value_or(false);
+    bool enabled = Fingerprint::cfg().get<bool>("lockout_enable");
     if (enabled) {
         mFailedCount++;
         int32_t lockoutTimedThreshold =
-                FingerprintHalProperties::lockout_timed_threshold().value_or(5);
+                Fingerprint::cfg().get<std::int32_t>("lockout_timed_threshold");
         int32_t lockoutPermanetThreshold =
-                FingerprintHalProperties::lockout_permanent_threshold().value_or(20);
+                Fingerprint::cfg().get<std::int32_t>("lockout_permanent_threshold");
         if (mFailedCount >= lockoutPermanetThreshold) {
             mCurrentMode = LockoutMode::kPermanent;
-            FingerprintHalProperties::lockout(true);
+            Fingerprint::cfg().set<bool>("lockout", true);
         } else if (mFailedCount >= lockoutTimedThreshold) {
             if (mCurrentMode == LockoutMode::kNone) {
                 mCurrentMode = LockoutMode::kTimed;
@@ -53,7 +54,7 @@
 FakeLockoutTracker::LockoutMode FakeLockoutTracker::getMode() {
     if (mCurrentMode == LockoutMode::kTimed) {
         int32_t lockoutTimedDuration =
-                FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
+                Fingerprint::cfg().get<std::int32_t>("lockout_timed_duration");
         if (Util::hasElapsed(mLockoutTimedStart, lockoutTimedDuration)) {
             mCurrentMode = LockoutMode::kNone;
             mLockoutTimedStart = 0;
@@ -68,11 +69,11 @@
 
     if (mLockoutTimedStart > 0) {
         int32_t lockoutTimedDuration =
-                FingerprintHalProperties::lockout_timed_duration().value_or(10 * 100);
+                Fingerprint::cfg().get<std::int32_t>("lockout_timed_duration");
         auto now = Util::getSystemNanoTime();
         auto elapsed = (now - mLockoutTimedStart) / 1000000LL;
         res = lockoutTimedDuration - elapsed;
-        LOG(INFO) << "xxxxxx: elapsed=" << elapsed << " now = " << now
+        LOG(INFO) << "elapsed=" << elapsed << " now = " << now
                   << " mLockoutTimedStart=" << mLockoutTimedStart << " res=" << res;
     }
 
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index 79b563e..dded54b 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -43,7 +43,7 @@
 }  // namespace
 
 Fingerprint::Fingerprint() : mWorker(MAX_WORKER_QUEUE_SIZE) {
-    std::string sensorTypeProp = FingerprintHalProperties::type().value_or("");
+    std::string sensorTypeProp = Fingerprint::cfg().get<std::string>("type");
     if (sensorTypeProp == "" || sensorTypeProp == "default" || sensorTypeProp == "rear") {
         mSensorType = FingerprintSensorType::REAR;
         mEngine = std::make_unique<FakeFingerprintEngineRear>();
@@ -68,15 +68,13 @@
             {HW_COMPONENT_ID, HW_VERSION, FW_VERSION, SERIAL_NUMBER, "" /* softwareVersion */},
             {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
              "" /* serialNumber */, SW_VERSION}};
-    auto sensorId = FingerprintHalProperties::sensor_id().value_or(SENSOR_ID);
-    auto sensorStrength =
-            FingerprintHalProperties::sensor_strength().value_or((int)SENSOR_STRENGTH);
-    auto maxEnrollments =
-            FingerprintHalProperties::max_enrollments().value_or(MAX_ENROLLMENTS_PER_USER);
-    auto navigationGuesture = FingerprintHalProperties::navigation_guesture().value_or(false);
-    auto detectInteraction = FingerprintHalProperties::detect_interaction().value_or(false);
-    auto displayTouch = FingerprintHalProperties::display_touch().value_or(true);
-    auto controlIllumination = FingerprintHalProperties::control_illumination().value_or(false);
+    auto sensorId = Fingerprint::cfg().get<std::int32_t>("sensor_id");
+    auto sensorStrength = Fingerprint::cfg().get<std::int32_t>("sensor_strength");
+    auto maxEnrollments = Fingerprint::cfg().get<std::int32_t>("max_enrollments");
+    auto navigationGuesture = Fingerprint::cfg().get<bool>("navigation_guesture");
+    auto detectInteraction = Fingerprint::cfg().get<bool>("detect_interaction");
+    auto displayTouch = Fingerprint::cfg().get<bool>("display_touch");
+    auto controlIllumination = Fingerprint::cfg().get<bool>("control_illumination");
 
     common::CommonProps commonProps = {sensorId, (common::SensorStrength)sensorStrength,
                                        maxEnrollments, componentInfo};
@@ -166,6 +164,14 @@
 
 void Fingerprint::resetConfigToDefault() {
     LOG(INFO) << __func__ << ": reset virtual HAL configuration to default";
+    Fingerprint::cfg().init();
+#ifdef FPS_DEBUGGABLE
+    clearConfigSysprop();
+#endif
+}
+
+void Fingerprint::clearConfigSysprop() {
+    LOG(INFO) << __func__ << ": clear all systprop configuration";
 #define RESET_CONFIG_O(__NAME__) \
     if (FingerprintHalProperties::__NAME__()) FingerprintHalProperties::__NAME__(std::nullopt)
 #define RESET_CONFIG_V(__NAME__)                       \
diff --git a/biometrics/fingerprint/aidl/default/FingerprintConfig.cpp b/biometrics/fingerprint/aidl/default/FingerprintConfig.cpp
new file mode 100644
index 0000000..82c5403
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/FingerprintConfig.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 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 "FingerprintConfig"
+
+#include "FingerprintConfig.h"
+
+#include <android-base/logging.h>
+
+#include <fingerprint.sysprop.h>
+
+using namespace ::android::fingerprint::virt;
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+// Wrapper to system property access functions
+#define CREATE_GETTER_SETTER_WRAPPER(_NAME_, _T_)                  \
+    ConfigValue _NAME_##Getter() {                                 \
+        return FingerprintHalProperties::_NAME_();                 \
+    }                                                              \
+    bool _NAME_##Setter(const ConfigValue& v) {                    \
+        return FingerprintHalProperties::_NAME_(std::get<_T_>(v)); \
+    }
+
+CREATE_GETTER_SETTER_WRAPPER(type, OptString)
+CREATE_GETTER_SETTER_WRAPPER(enrollments, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(enrollment_hit, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(next_enrollment, OptString)
+CREATE_GETTER_SETTER_WRAPPER(authenticator_id, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(challenge, OptInt64)
+CREATE_GETTER_SETTER_WRAPPER(sensor_id, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(sensor_location, OptString)
+CREATE_GETTER_SETTER_WRAPPER(sensor_strength, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_fails, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_authenticate_acquired, OptString)
+CREATE_GETTER_SETTER_WRAPPER(operation_enroll_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_enroll_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_error, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_latency, OptIntVec)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(operation_detect_interaction_acquired, OptString)
+CREATE_GETTER_SETTER_WRAPPER(max_enrollments, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(navigation_guesture, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(detect_interaction, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(display_touch, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(control_illumination, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_enable, OptBool)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_threshold, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_timed_duration, OptInt32)
+CREATE_GETTER_SETTER_WRAPPER(lockout_permanent_threshold, OptInt32)
+
+// Name, Getter, Setter, Parser and default value
+#define NGS(_NAME_) #_NAME_, _NAME_##Getter, _NAME_##Setter
+static Config::Data configData[] = {
+        {NGS(type), &Config::parseString, "rear"},
+        {NGS(enrollments), &Config::parseIntVec, ""},
+        {NGS(enrollment_hit), &Config::parseInt32, "0"},
+        {NGS(next_enrollment), &Config::parseString, ""},
+        {NGS(authenticator_id), &Config::parseInt64, "0"},
+        {NGS(challenge), &Config::parseInt64, ""},
+        {NGS(sensor_id), &Config::parseInt32, "5"},
+        {NGS(sensor_location), &Config::parseString, ""},
+        {NGS(sensor_strength), &Config::parseInt32, "2"},  // STRONG
+        {NGS(operation_authenticate_fails), &Config::parseBool, "false"},
+        {NGS(operation_authenticate_latency), &Config::parseIntVec, ""},
+        {NGS(operation_authenticate_duration), &Config::parseInt32, "10"},
+        {NGS(operation_authenticate_error), &Config::parseInt32, "0"},
+        {NGS(operation_authenticate_acquired), &Config::parseString, "1"},
+        {NGS(operation_enroll_error), &Config::parseInt32, "0"},
+        {NGS(operation_enroll_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_latency), &Config::parseIntVec, ""},
+        {NGS(operation_detect_interaction_error), &Config::parseInt32, "0"},
+        {NGS(operation_detect_interaction_duration), &Config::parseInt32, "10"},
+        {NGS(operation_detect_interaction_acquired), &Config::parseString, "1"},
+        {NGS(max_enrollments), &Config::parseInt32, "5"},
+        {NGS(navigation_guesture), &Config::parseBool, "false"},
+        {NGS(detect_interaction), &Config::parseBool, "false"},
+        {NGS(display_touch), &Config::parseBool, "true"},
+        {NGS(control_illumination), &Config::parseBool, "false"},
+        {NGS(lockout), &Config::parseBool, "false"},
+        {NGS(lockout_enable), &Config::parseBool, "false"},
+        {NGS(lockout_timed_threshold), &Config::parseInt32, "5"},
+        {NGS(lockout_timed_duration), &Config::parseInt32, "10000"},
+        {NGS(lockout_permanent_threshold), &Config::parseInt32, "20"},
+};
+
+Config::Data* FingerprintConfig::getConfigData(int* size) {
+    *size = sizeof(configData) / sizeof(configData[0]);
+    return configData;
+}
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/include/Fingerprint.h b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
index 2bd66d4..1576f07 100644
--- a/biometrics/fingerprint/aidl/default/include/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/include/Fingerprint.h
@@ -23,6 +23,7 @@
 #include "FakeFingerprintEngineSide.h"
 #include "FakeFingerprintEngineUdfps.h"
 
+#include "FingerprintConfig.h"
 #include "Session.h"
 #include "thread/WorkerThread.h"
 
@@ -40,10 +41,20 @@
     binder_status_t dump(int fd, const char** args, uint32_t numArgs);
     binder_status_t handleShellCommand(int in, int out, int err, const char** argv, uint32_t argc);
 
+    static FingerprintConfig& cfg() {
+        static FingerprintConfig* cfg = nullptr;
+        if (cfg == nullptr) {
+            cfg = new FingerprintConfig();
+            cfg->init();
+        }
+        return *cfg;
+    }
+
   private:
     void resetConfigToDefault();
     void onHelp(int);
     void onSimFingerDown();
+    void clearConfigSysprop();
 
     std::unique_ptr<FakeFingerprintEngine> mEngine;
     WorkerThread mWorker;
diff --git a/biometrics/fingerprint/aidl/default/include/FingerprintConfig.h b/biometrics/fingerprint/aidl/default/include/FingerprintConfig.h
new file mode 100644
index 0000000..bd1ad4c
--- /dev/null
+++ b/biometrics/fingerprint/aidl/default/include/FingerprintConfig.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#pragma once
+
+#include "config/Config.h"
+
+namespace aidl::android::hardware::biometrics::fingerprint {
+
+class FingerprintConfig : public Config {
+    Config::Data* getConfigData(int* size) override;
+};
+
+}  // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index 8b06c8e..039f25e 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -21,6 +21,7 @@
 #include <aidl/android/hardware/biometrics/fingerprint/BnSessionCallback.h>
 
 #include "FakeFingerprintEngine.h"
+#include "Fingerprint.h"
 #include "util/Util.h"
 
 using namespace ::android::fingerprint::virt;
@@ -125,21 +126,20 @@
 class FakeFingerprintEngineTest : public ::testing::Test {
   protected:
     void SetUp() override {
-        FingerprintHalProperties::operation_enroll_latency({0});
-        FingerprintHalProperties::operation_authenticate_latency({0});
-        FingerprintHalProperties::operation_detect_interaction_latency({0});
+        Fingerprint::cfg().setopt<OptIntVec>("operation_enroll_latency", {0});
+        Fingerprint::cfg().setopt<OptIntVec>("operation_authenticate_latency", {0});
+        Fingerprint::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {0});
         mCallback = ndk::SharedRefBase::make<TestSessionCallback>();
     }
 
     void TearDown() override {
-        FingerprintHalProperties::operation_authenticate_error(0);
-        FingerprintHalProperties::operation_detect_interaction_error(0);
-        FingerprintHalProperties::operation_authenticate_acquired("");
-        FingerprintHalProperties::operation_enroll_latency({});
-        FingerprintHalProperties::operation_authenticate_latency({});
-        FingerprintHalProperties::operation_detect_interaction_latency({});
-        FingerprintHalProperties::operation_authenticate_fails(false);
-        FingerprintHalProperties::operation_detect_interaction_latency({});
+        Fingerprint::cfg().set<std::int32_t>("operation_authenticate_error", 0);
+        Fingerprint::cfg().set<std::int32_t>("operation_detect_interaction_error", 0);
+        Fingerprint::cfg().set<std::string>("operation_authenticate_acquired", "");
+        Fingerprint::cfg().setopt<OptIntVec>("operation_enroll_latency", {});
+        Fingerprint::cfg().setopt<OptIntVec>("operation_authenticate_latency", {});
+        Fingerprint::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
+        Fingerprint::cfg().set<bool>("operation_authenticate_fails", false);
     }
 
     FakeFingerprintEngine mEngine;
@@ -149,58 +149,58 @@
 
 TEST_F(FakeFingerprintEngineTest, GenerateChallenge) {
     mEngine.generateChallengeImpl(mCallback.get());
-    ASSERT_EQ(FingerprintHalProperties::challenge().value(), mCallback->mLastChallenge);
+    ASSERT_EQ(Fingerprint::cfg().get<std::int64_t>("challenge"), mCallback->mLastChallenge);
 }
 
 TEST_F(FakeFingerprintEngineTest, RevokeChallenge) {
-    auto challenge = FingerprintHalProperties::challenge().value_or(10);
+    auto challenge = Fingerprint::cfg().get<std::int64_t>("challenge");
     mEngine.revokeChallengeImpl(mCallback.get(), challenge);
-    ASSERT_FALSE(FingerprintHalProperties::challenge().has_value());
+    ASSERT_FALSE((Fingerprint::cfg().getopt<OptInt64>("challenge")).has_value());
     ASSERT_EQ(challenge, mCallback->mLastChallengeRevoked);
 }
 
 TEST_F(FakeFingerprintEngineTest, ResetLockout) {
-    FingerprintHalProperties::lockout(true);
+    Fingerprint::cfg().get<bool>("lockout");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.resetLockoutImpl(mCallback.get(), hat);
-    ASSERT_FALSE(FingerprintHalProperties::lockout().value_or(true));
+    ASSERT_FALSE(Fingerprint::cfg().get<bool>("lockout"));
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticatorId) {
-    FingerprintHalProperties::enrollments({1});
-    FingerprintHalProperties::authenticator_id(50);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1});
+    Fingerprint::cfg().set<std::int64_t>("authenticator_id", 50);
     mEngine.getAuthenticatorIdImpl(mCallback.get());
     ASSERT_EQ(50, mCallback->mLastAuthenticatorId);
     ASSERT_FALSE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticatorIdInvalidate) {
-    FingerprintHalProperties::authenticator_id(500);
+    Fingerprint::cfg().set<std::int64_t>("authenticator_id", 500);
     mEngine.invalidateAuthenticatorIdImpl(mCallback.get());
-    ASSERT_NE(500, FingerprintHalProperties::authenticator_id().value());
+    ASSERT_NE(500, Fingerprint::cfg().get<std::int64_t>("authenticator_id"));
     ASSERT_TRUE(mCallback->mAuthenticatorIdInvalidated);
 }
 
 TEST_F(FakeFingerprintEngineTest, Enroll) {
-    FingerprintHalProperties::enrollments({});
-    FingerprintHalProperties::next_enrollment("4:0,0:true");
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {});
+    Fingerprint::cfg().set<std::string>("next_enrollment", "4:0,0:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kEnroll);
     mEngine.fingerDownAction();
-    ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
-    ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
+    ASSERT_FALSE(Fingerprint::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(1, Fingerprint::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_EQ(4, Fingerprint::cfg().getopt<OptIntVec>("enrollments")[0].value());
     ASSERT_EQ(4, mCallback->mLastEnrolled);
     ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
 }
 
 TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
-    FingerprintHalProperties::enrollments({});
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {});
     auto next = "4:0,0:true";
-    FingerprintHalProperties::next_enrollment(next);
+    Fingerprint::cfg().set<std::string>("next_enrollment", next);
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mCancel.set_value();
     mEngine.notifyFingerdown();
@@ -208,35 +208,35 @@
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::CANCELED, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
-    ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
-    ASSERT_EQ(next, FingerprintHalProperties::next_enrollment().value_or(""));
+    ASSERT_EQ(0, Fingerprint::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_EQ(next, Fingerprint::cfg().get<std::string>("next_enrollment"));
 }
 
 TEST_F(FakeFingerprintEngineTest, EnrollFail) {
-    FingerprintHalProperties::enrollments({});
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {});
     auto next = "2:0,0:false";
-    FingerprintHalProperties::next_enrollment(next);
+    Fingerprint::cfg().set<std::string>("next_enrollment", next);
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     mEngine.fingerDownAction();
     ASSERT_EQ(Error::UNABLE_TO_PROCESS, mCallback->mError);
     ASSERT_EQ(-1, mCallback->mLastEnrolled);
-    ASSERT_EQ(0, FingerprintHalProperties::enrollments().size());
-    ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
+    ASSERT_EQ(0, Fingerprint::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_FALSE(Fingerprint::cfg().getopt<OptString>("next_enrollment").has_value());
 }
 
 TEST_F(FakeFingerprintEngineTest, EnrollAcquired) {
-    FingerprintHalProperties::enrollments({});
-    FingerprintHalProperties::next_enrollment("4:0,5-[12,1013]:true");
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {});
+    Fingerprint::cfg().set<std::string>("next_enrollment", "4:0,5-[12,1013]:true");
     keymaster::HardwareAuthToken hat{.mac = {2, 4}};
     int32_t prevCnt = mCallback->mLastAcquiredCount;
     mEngine.notifyFingerdown();
     mEngine.enrollImpl(mCallback.get(), hat, mCancel.get_future());
     mEngine.fingerDownAction();
-    ASSERT_FALSE(FingerprintHalProperties::next_enrollment().has_value());
-    ASSERT_EQ(1, FingerprintHalProperties::enrollments().size());
-    ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
+    ASSERT_FALSE(Fingerprint::cfg().getopt<OptString>("next_enrollment").has_value());
+    ASSERT_EQ(1, Fingerprint::cfg().getopt<OptIntVec>("enrollments").size());
+    ASSERT_EQ(4, Fingerprint::cfg().getopt<OptIntVec>("enrollments")[0].value());
     ASSERT_EQ(4, mCallback->mLastEnrolled);
     ASSERT_EQ(prevCnt + 3, mCallback->mLastAcquiredCount);
     ASSERT_EQ(7, mCallback->mLastAcquiredInfo);
@@ -244,8 +244,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, Authenticate) {
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
@@ -257,8 +257,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
-    FingerprintHalProperties::enrollments({2});
-    FingerprintHalProperties::enrollment_hit(2);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
     mCancel.set_value();
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
@@ -268,8 +268,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateNotSet) {
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit({});
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().setopt<OptInt32>("enrollment_hit", std::nullopt);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -277,8 +277,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateNotEnrolled) {
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(3);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 3);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -287,9 +287,9 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateLockout) {
-    FingerprintHalProperties::enrollments({22, 2});
-    FingerprintHalProperties::enrollment_hit(2);
-    FingerprintHalProperties::lockout(true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {22, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
+    Fingerprint::cfg().set<bool>("lockout", true);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -298,7 +298,7 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateError8) {
-    FingerprintHalProperties::operation_authenticate_error(8);
+    Fingerprint::cfg().set<std::int32_t>("operation_authenticate_error", 8);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -307,7 +307,7 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateError9) {
-    FingerprintHalProperties::operation_authenticate_error(1009);
+    Fingerprint::cfg().set<std::int32_t>("operation_authenticate_error", 1009);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -316,7 +316,7 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateFails) {
-    FingerprintHalProperties::operation_authenticate_fails(true);
+    Fingerprint::cfg().set<bool>("operation_authenticate_fails", true);
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
     mEngine.fingerDownAction();
@@ -325,10 +325,10 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
-    FingerprintHalProperties::lockout(false);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
-    FingerprintHalProperties::operation_authenticate_acquired("4,1009");
+    Fingerprint::cfg().set<bool>("lockout", false);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
+    Fingerprint::cfg().set<std::string>("operation_authenticate_acquired", "4,1009");
     int32_t prevCount = mCallback->mLastAcquiredCount;
     mEngine.notifyFingerdown();
     mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
@@ -341,10 +341,10 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetect) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
-    FingerprintHalProperties::operation_detect_interaction_acquired("");
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
+    Fingerprint::cfg().set<std::string>("operation_detect_interaction_acquired", "");
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kDetectInteract);
@@ -355,9 +355,9 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
     mCancel.set_value();
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
@@ -367,9 +367,9 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectNotSet) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit({});
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().setopt<OptInt32>("enrollment_hit", std::nullopt);
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
@@ -377,8 +377,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectNotEnrolled) {
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(25);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 25);
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
@@ -386,8 +386,8 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectError) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::operation_detect_interaction_error(8);
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().set<std::int32_t>("operation_detect_interaction_error", 8);
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
     mEngine.fingerDownAction();
@@ -397,10 +397,10 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, InteractionDetectAcquired) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
-    FingerprintHalProperties::operation_detect_interaction_acquired("4,1013");
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
+    Fingerprint::cfg().set<std::string>("operation_detect_interaction_acquired", "4,1013");
     int32_t prevCount = mCallback->mLastAcquiredCount;
     mEngine.notifyFingerdown();
     mEngine.detectInteractionImpl(mCallback.get(), mCancel.get_future());
@@ -412,10 +412,10 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, EnumerateEnrolled) {
-    FingerprintHalProperties::enrollments({2, 4, 8});
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {2, 4, 8});
     mEngine.enumerateEnrollmentsImpl(mCallback.get());
     ASSERT_EQ(3, mCallback->mLastEnrollmentEnumerated.size());
-    for (auto id : FingerprintHalProperties::enrollments()) {
+    for (auto id : Fingerprint::cfg().getopt<OptIntVec>("enrollments")) {
         ASSERT_TRUE(std::find(mCallback->mLastEnrollmentEnumerated.begin(),
                               mCallback->mLastEnrollmentEnumerated.end(),
                               id) != mCallback->mLastEnrollmentEnumerated.end());
@@ -423,9 +423,9 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, RemoveEnrolled) {
-    FingerprintHalProperties::enrollments({2, 4, 8, 1});
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {2, 4, 8, 1});
     mEngine.removeEnrollmentsImpl(mCallback.get(), {2, 8});
-    auto enrolls = FingerprintHalProperties::enrollments();
+    auto enrolls = Fingerprint::cfg().getopt<OptIntVec>("enrollments");
     ASSERT_EQ(2, mCallback->mLastEnrollmentRemoved.size());
     for (auto id : {2, 8}) {
         ASSERT_TRUE(std::find(mCallback->mLastEnrollmentRemoved.begin(),
@@ -509,17 +509,17 @@
 }
 
 TEST_F(FakeFingerprintEngineTest, randomLatency) {
-    FingerprintHalProperties::operation_detect_interaction_latency({});
-    ASSERT_EQ(DEFAULT_LATENCY,
-              mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
-    FingerprintHalProperties::operation_detect_interaction_latency({10});
-    ASSERT_EQ(10,
-              mEngine.getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
-    FingerprintHalProperties::operation_detect_interaction_latency({1, 1000});
+    Fingerprint::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {});
+    ASSERT_EQ(DEFAULT_LATENCY, mEngine.getLatency(Fingerprint::cfg().getopt<OptIntVec>(
+                                       "operation_detect_interaction_latency")));
+    Fingerprint::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {10});
+    ASSERT_EQ(10, mEngine.getLatency(Fingerprint::cfg().getopt<OptIntVec>(
+                          "operation_detect_interaction_latency")));
+    Fingerprint::cfg().setopt<OptIntVec>("operation_detect_interaction_latency", {1, 1000});
     std::set<int32_t> latencySet;
     for (int i = 0; i < 100; i++) {
         latencySet.insert(mEngine.getLatency(
-                FingerprintHalProperties::operation_detect_interaction_latency()));
+                Fingerprint::cfg().getopt<OptIntVec>("operation_detect_interaction_latency")));
     }
     ASSERT_TRUE(latencySet.size() > 95);
 }
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
index 5a30db1..eb45f98 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineUdfpsTest.cpp
@@ -23,6 +23,7 @@
 
 #include "FakeFingerprintEngine.h"
 #include "FakeFingerprintEngineUdfps.h"
+#include "Fingerprint.h"
 
 using namespace ::android::fingerprint::virt;
 using namespace ::aidl::android::hardware::biometrics::fingerprint;
@@ -99,7 +100,7 @@
 
     void TearDown() override {
         // reset to default
-        FingerprintHalProperties::sensor_location("");
+        Fingerprint::cfg().set<std::string>("sensor_location", "");
     }
 
     FakeFingerprintEngineUdfps mEngine;
@@ -113,14 +114,14 @@
 
 TEST_F(FakeFingerprintEngineUdfpsTest, getSensorLocationOk) {
     auto loc = "100:200:30";
-    FingerprintHalProperties::sensor_location(loc);
+    Fingerprint::cfg().set<std::string>("sensor_location", loc);
     SensorLocation sc = mEngine.getSensorLocation();
     ASSERT_TRUE(sc.sensorLocationX == 100);
     ASSERT_TRUE(sc.sensorLocationY == 200);
     ASSERT_TRUE(sc.sensorRadius == 30);
 
     loc = "100:200:30:screen1";
-    FingerprintHalProperties::sensor_location(loc);
+    Fingerprint::cfg().set<std::string>("sensor_location", loc);
     sc = mEngine.getSensorLocation();
     ASSERT_TRUE(sc.sensorLocationX == 100);
     ASSERT_TRUE(sc.sensorLocationY == 200);
@@ -132,7 +133,7 @@
     const std::vector<std::string> badStr{"", "100", "10:20", "10,20,5", "a:b:c"};
     SensorLocation sc;
     for (const auto& s : badStr) {
-        FingerprintHalProperties::sensor_location(s);
+        Fingerprint::cfg().set<std::string>("sensor_location", s);
         sc = mEngine.getSensorLocation();
         ASSERT_TRUE(isDefaultLocation(sc));
     }
@@ -158,7 +159,7 @@
     std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
     std::promise<void> cancel;
     keymaster::HardwareAuthToken hat{.mac = {5, 6}};
-    FingerprintHalProperties::next_enrollment("5:0,0:true");
+    Fingerprint::cfg().set<std::string>("next_enrollment", "5:0,0:true");
     mEngine.notifyFingerdown();
     mEngine.enrollImpl(cb.get(), hat, cancel.get_future());
     ASSERT_TRUE(mEngine.getWorkMode() == FakeFingerprintEngineUdfps::WorkMode::kEnroll);
@@ -169,10 +170,10 @@
 }
 
 TEST_F(FakeFingerprintEngineUdfpsTest, detectInteraction) {
-    FingerprintHalProperties::detect_interaction(true);
-    FingerprintHalProperties::enrollments({1, 2});
-    FingerprintHalProperties::enrollment_hit(2);
-    FingerprintHalProperties::operation_detect_interaction_acquired("");
+    Fingerprint::cfg().set<bool>("detect_interaction", true);
+    Fingerprint::cfg().setopt<OptIntVec>("enrollments", {1, 2});
+    Fingerprint::cfg().set<std::int32_t>("enrollment_hit", 2);
+    Fingerprint::cfg().set<std::string>("operation_detect_interaction_acquired", "");
     std::shared_ptr<TestSessionCallback> cb = ndk::SharedRefBase::make<TestSessionCallback>();
     std::promise<void> cancel;
     mEngine.notifyFingerdown();
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
index 93c6f84..3c12b6d 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeLockoutTrackerTest.cpp
@@ -21,6 +21,7 @@
 #include <android-base/logging.h>
 
 #include "FakeLockoutTracker.h"
+#include "Fingerprint.h"
 #include "util/Util.h"
 
 using namespace ::android::fingerprint::virt;
@@ -35,32 +36,33 @@
     static constexpr int32_t LOCKOUT_TIMED_DURATION = 100;
 
     void SetUp() override {
-        FingerprintHalProperties::lockout_timed_threshold(LOCKOUT_TIMED_THRESHOLD);
-        FingerprintHalProperties::lockout_timed_duration(LOCKOUT_TIMED_DURATION);
-        FingerprintHalProperties::lockout_permanent_threshold(LOCKOUT_PERMANENT_THRESHOLD);
+        Fingerprint::cfg().set<std::int32_t>("lockout_timed_threshold", LOCKOUT_TIMED_THRESHOLD);
+        Fingerprint::cfg().set<std::int32_t>("lockout_timed_duration", LOCKOUT_TIMED_DURATION);
+        Fingerprint::cfg().set<std::int32_t>("lockout_permanent_threshold",
+                                             LOCKOUT_PERMANENT_THRESHOLD);
     }
 
     void TearDown() override {
         // reset to default
-        FingerprintHalProperties::lockout_timed_threshold(5);
-        FingerprintHalProperties::lockout_timed_duration(20);
-        FingerprintHalProperties::lockout_permanent_threshold(10000);
-        FingerprintHalProperties::lockout_enable(false);
-        FingerprintHalProperties::lockout(false);
+        Fingerprint::cfg().set<std::int32_t>("lockout_timed_threshold", 5);
+        Fingerprint::cfg().set<std::int32_t>("lockout_timed_duration", 20);
+        Fingerprint::cfg().set<std::int32_t>("lockout_permanent_threshold", 10000);
+        Fingerprint::cfg().set<bool>("lockout_enable", false);
+        Fingerprint::cfg().set<bool>("lockout", false);
     }
 
     FakeLockoutTracker mLockoutTracker;
 };
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptDisable) {
-    FingerprintHalProperties::lockout_enable(false);
+    Fingerprint::cfg().set<bool>("lockout_enable", false);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD + 1; i++) mLockoutTracker.addFailedAttempt();
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kNone);
     mLockoutTracker.reset();
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptLockoutTimed) {
-    FingerprintHalProperties::lockout_enable(true);
+    Fingerprint::cfg().set<bool>("lockout_enable", true);
     for (int i = 0; i < LOCKOUT_TIMED_THRESHOLD; i++) mLockoutTracker.addFailedAttempt();
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kTimed);
     // time left
@@ -77,12 +79,12 @@
 }
 
 TEST_F(FakeLockoutTrackerTest, addFailedAttemptPermanent) {
-    FingerprintHalProperties::lockout_enable(true);
+    Fingerprint::cfg().set<bool>("lockout_enable", true);
     for (int i = 0; i < LOCKOUT_PERMANENT_THRESHOLD - 1; i++) mLockoutTracker.addFailedAttempt();
     ASSERT_NE(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
     mLockoutTracker.addFailedAttempt();
     ASSERT_EQ(mLockoutTracker.getMode(), FakeLockoutTracker::LockoutMode::kPermanent);
-    ASSERT_TRUE(FingerprintHalProperties::lockout());
+    ASSERT_TRUE(Fingerprint::cfg().get<bool>("lockout"));
     mLockoutTracker.reset();
 }