Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 343ca94b authored by Jeff Pu's avatar Jeff Pu
Browse files

Fingerprint virtual HAL checkin (part 2)

- acquiredInfo support for HAL operations
- error insertions
- FPS configurations

Bug: 230515082
Bug: 230515086
Test: atest FakeFingerprintEngineTest
      atest FakeFingerprintEngineUdfpsTest
      atest --no-bazel-mode VtsHalBiometricsFingerprintTargetTest

Change-Id: Iedd1056e516358c3c0a99bd4a720016cc0f880e4
parent 780b6e41
Loading
Loading
Loading
Loading
+211 −42
Original line number Diff line number Diff line
@@ -56,43 +56,58 @@ void FakeFingerprintEngine::enrollImpl(ISessionCallback* cb,
        return;
    }

    if (FingerprintHalProperties::operation_enroll_fails().value_or(false)) {
        LOG(ERROR) << "Fail: operation_enroll_fails";
        cb->onError(Error::VENDOR, 0 /* vendorError */);
    // Force error-out
    auto err = FingerprintHalProperties::operation_enroll_error().value_or(0);
    if (err != 0) {
        LOG(ERROR) << "Fail: operation_enroll_error";
        auto ec = convertError(err);
        cb->onError(ec.first, ec.second);
        return;
    }

    // format is "<id>:<progress_ms>,<progress_ms>,...:<result>
    // Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
    auto nextEnroll = FingerprintHalProperties::next_enrollment().value_or("");
    auto parts = Util::split(nextEnroll, ":");
    if (parts.size() != 3) {
        LOG(ERROR) << "Fail: invalid next_enrollment";
        LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
        cb->onError(Error::VENDOR, 0 /* vendorError */);
        return;
    }
    auto enrollmentId = std::stoi(parts[0]);
    auto progress = Util::split(parts[1], ",");
    for (size_t i = 0; i < progress.size(); i++) {
        auto left = progress.size() - i - 1;
        SLEEP_MS(std::stoi(progress[i]));
    auto progress = parseEnrollmentCapture(parts[1]);
    for (size_t i = 0; i < progress.size(); i += 2) {
        auto left = (progress.size() - i) / 2 - 1;
        auto duration = progress[i][0];
        auto acquired = progress[i + 1];
        auto N = acquired.size();

        for (int j = 0; j < N; j++) {
            SLEEP_MS(duration / N);

            if (shouldCancel(cancel)) {
                LOG(ERROR) << "Fail: cancel";
                cb->onError(Error::CANCELED, 0 /* vendorCode */);
                return;
            }
            auto ac = convertAcquiredInfo(acquired[j]);
            cb->onAcquired(ac.first, ac.second);
        }

        cb->onAcquired(AcquiredInfo::GOOD, 0 /* vendorCode */);
        if (left == 0 && !IS_TRUE(parts[2])) {  // end and failed
            LOG(ERROR) << "Fail: requested by caller: " << nextEnroll;
            FingerprintHalProperties::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();
                enrollments.emplace_back(enrollmentId);
                FingerprintHalProperties::enrollments(enrollments);
                FingerprintHalProperties::next_enrollment({});
                // change authenticatorId after new enrollment
                auto id = FingerprintHalProperties::authenticator_id().value_or(0);
                auto newId = id + 1;
                FingerprintHalProperties::authenticator_id(newId);
                LOG(INFO) << "Enrolled: " << enrollmentId;
            }
            cb->onEnrollmentProgress(enrollmentId, left);
@@ -104,12 +119,31 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
                                             const std::future<void>& cancel) {
    BEGIN_OP(FingerprintHalProperties::operation_authenticate_latency().value_or(DEFAULT_LATENCY));

    auto now = Util::getSystemNanoTime();
    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(0);
    int64_t now = Util::getSystemNanoTime();
    int64_t duration = FingerprintHalProperties::operation_authenticate_duration().value_or(10);
    auto acquired = FingerprintHalProperties::operation_authenticate_acquired().value_or("1");
    auto acquiredInfos = parseIntSequence(acquired);
    int N = acquiredInfos.size();

    if (N == 0) {
        LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
        return;
    }

    int i = 0;
    do {
        if (FingerprintHalProperties::operation_authenticate_fails().value_or(false)) {
            LOG(ERROR) << "Fail: operation_authenticate_fails";
            cb->onError(Error::VENDOR, 0 /* vendorError */);
            cb->onAuthenticationFailed();
            return;
        }

        auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
        if (err != 0) {
            LOG(ERROR) << "Fail: operation_authenticate_error";
            auto ec = convertError(err);
            cb->onError(ec.first, ec.second);
            return;
        }

@@ -126,20 +160,25 @@ void FakeFingerprintEngine::authenticateImpl(ISessionCallback* cb, int64_t /* op
            return;
        }

        if (i < N) {
            auto ac = convertAcquiredInfo(acquiredInfos[i]);
            cb->onAcquired(ac.first, ac.second);
            i++;
        }

        SLEEP_MS(duration / N);
    } while (!Util::hasElapsed(now, duration));

    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
    auto enrolls = FingerprintHalProperties::enrollments();
    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
    if (id > 0 && isEnrolled) {
        cb->onAuthenticationSucceeded(id, {} /* hat */);
        return;
        }

        SLEEP_MS(100);
    } while (!Util::hasElapsed(now, duration));

    LOG(ERROR) << "Fail: not enrolled";
    } else {
        LOG(ERROR) << "Fail: fingerprint not enrolled";
        cb->onAuthenticationFailed();
    cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
    }
}

void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
@@ -147,9 +186,26 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
    BEGIN_OP(FingerprintHalProperties::operation_detect_interaction_latency().value_or(
            DEFAULT_LATENCY));

    if (FingerprintHalProperties::operation_detect_interaction_fails().value_or(false)) {
        LOG(ERROR) << "Fail: operation_detect_interaction_fails";
        cb->onError(Error::VENDOR, 0 /* vendorError */);
    int64_t duration =
            FingerprintHalProperties::operation_detect_interaction_duration().value_or(10);
    auto acquired = FingerprintHalProperties::operation_detect_interaction_acquired().value_or("1");
    auto acquiredInfos = parseIntSequence(acquired);
    int N = acquiredInfos.size();
    int64_t now = Util::getSystemNanoTime();

    if (N == 0) {
        LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
        return;
    }

    int i = 0;
    do {
        auto err = FingerprintHalProperties::operation_detect_interaction_error().value_or(0);
        if (err != 0) {
            LOG(ERROR) << "Fail: operation_detect_interaction_error";
            auto ec = convertError(err);
            cb->onError(ec.first, ec.second);
            return;
        }

@@ -159,6 +215,14 @@ void FakeFingerprintEngine::detectInteractionImpl(ISessionCallback* cb,
            return;
        }

        if (i < N) {
            auto ac = convertAcquiredInfo(acquiredInfos[i]);
            cb->onAcquired(ac.first, ac.second);
            i++;
        }
        SLEEP_MS(duration / N);
    } while (!Util::hasElapsed(now, duration));

    auto id = FingerprintHalProperties::enrollment_hit().value_or(0);
    auto enrolls = FingerprintHalProperties::enrollments();
    auto isEnrolled = std::find(enrolls.begin(), enrolls.end(), id) != enrolls.end();
@@ -211,24 +275,37 @@ void FakeFingerprintEngine::removeEnrollmentsImpl(ISessionCallback* cb,

void FakeFingerprintEngine::getAuthenticatorIdImpl(ISessionCallback* cb) {
    BEGIN_OP(0);
    int64_t authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
    if (FingerprintHalProperties::enrollments().size() > 0 && authenticatorId == 0) {
        authenticatorId = 99999999;  // default authenticatorId, TODO(b/230515082)
    int64_t authenticatorId;
    if (FingerprintHalProperties::enrollments().size() == 0) {
        authenticatorId = 0;
    } else {
        authenticatorId = FingerprintHalProperties::authenticator_id().value_or(0);
        if (authenticatorId == 0) authenticatorId = 1;
    }
    cb->onAuthenticatorIdRetrieved(authenticatorId);
}

void FakeFingerprintEngine::invalidateAuthenticatorIdImpl(ISessionCallback* cb) {
    BEGIN_OP(0);
    int64_t newId;
    if (FingerprintHalProperties::enrollments().size() == 0) {
        newId = 0;
    } else {
        auto id = FingerprintHalProperties::authenticator_id().value_or(0);
    auto newId = id + 1;
        newId = id + 1;
    }
    FingerprintHalProperties::authenticator_id(newId);
    cb->onAuthenticatorIdInvalidated(newId);
}

void FakeFingerprintEngine::resetLockoutImpl(ISessionCallback* cb,
                                             const keymaster::HardwareAuthToken& /*hat*/) {
                                             const keymaster::HardwareAuthToken& hat) {
    BEGIN_OP(0);
    if (hat.mac.empty()) {
        LOG(ERROR) << "Fail: hat in resetLockout()";
        cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
        return;
    }
    FingerprintHalProperties::lockout(false);
    cb->onLockoutCleared();
}
@@ -286,4 +363,96 @@ SensorLocation FakeFingerprintEngine::defaultSensorLocation() {
    return {0 /* displayId (not used) */, 0 /* sensorLocationX */, 0 /* sensorLocationY */,
            0 /* sensorRadius */, "" /* display */};
}

std::vector<int32_t> FakeFingerprintEngine::parseIntSequence(const std::string& str,
                                                             const std::string& sep) {
    std::vector<std::string> seqs = Util::split(str, sep);
    std::vector<int32_t> res;

    for (const auto& seq : seqs) {
        int32_t val;
        if (ParseInt(seq, &val)) {
            res.push_back(val);
        } else {
            LOG(WARNING) << "Invalid int sequence:" + str;
            res.clear();
            break;
        }
    }

    return res;
}

std::vector<std::vector<int32_t>> FakeFingerprintEngine::parseEnrollmentCapture(
        const std::string& str) {
    std::vector<int32_t> defaultAcquiredInfo = {(int32_t)AcquiredInfo::GOOD};
    std::vector<std::vector<int32_t>> res;
    int i = 0, N = str.length();
    std::size_t found = 0;
    bool aborted = true;

    while (found != std::string::npos) {
        std::string durationStr, acquiredStr;
        found = str.find_first_of("-,", i);
        if (found == std::string::npos) {
            if (N - i < 1) break;
            durationStr = str.substr(i, N - i);
        } else {
            durationStr = str.substr(i, found - i);
            if (str[found] == '-') {
                found = str.find_first_of('[', found + 1);
                if (found == std::string::npos) break;
                i = found + 1;
                found = str.find_first_of(']', found + 1);
                if (found == std::string::npos) break;
                acquiredStr = str.substr(i, found - i);
                found = str.find_first_of(',', found + 1);
            }
        }
        std::vector<int32_t> duration{0};
        if (!ParseInt(durationStr, &duration[0])) break;
        res.push_back(duration);
        if (!acquiredStr.empty()) {
            std::vector<int32_t> acquiredInfo = parseIntSequence(acquiredStr);
            if (acquiredInfo.empty()) break;
            res.push_back(acquiredInfo);
        } else
            res.push_back(defaultAcquiredInfo);

        i = found + 1;
        if (found == std::string::npos || found == N - 1) aborted = false;
    }

    if (aborted) {
        LOG(ERROR) << "Failed to parse enrollment captures:" + str;
        res.clear();
    }

    return res;
}

std::pair<AcquiredInfo, int32_t> FakeFingerprintEngine::convertAcquiredInfo(int32_t code) {
    std::pair<AcquiredInfo, int32_t> res;
    if (code > FINGERPRINT_ACQUIRED_VENDOR_BASE) {
        res.first = AcquiredInfo::VENDOR;
        res.second = code - FINGERPRINT_ACQUIRED_VENDOR_BASE;
    } else {
        res.first = (AcquiredInfo)code;
        res.second = 0;
    }
    return res;
}

std::pair<Error, int32_t> FakeFingerprintEngine::convertError(int32_t code) {
    std::pair<Error, int32_t> res;
    if (code > FINGERPRINT_ERROR_VENDOR_BASE) {
        res.first = Error::VENDOR;
        res.second = code - FINGERPRINT_ERROR_VENDOR_BASE;
    } else {
        res.first = (Error)code;
        res.second = 0;
    }
    return res;
}

}  // namespace aidl::android::hardware::biometrics::fingerprint
+16 −4
Original line number Diff line number Diff line
@@ -65,8 +65,18 @@ ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
            {SW_COMPONENT_ID, "" /* hardwareVersion */, "" /* firmwareVersion */,
             "" /* serialNumber */, SW_VERSION}};

    common::CommonProps commonProps = {SENSOR_ID, SENSOR_STRENGTH, MAX_ENROLLMENTS_PER_USER,
                                       componentInfo};
    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);

    common::CommonProps commonProps = {sensorId, (common::SensorStrength)sensorStrength,
                                       maxEnrollments, componentInfo};

    SensorLocation sensorLocation = mEngine->getSensorLocation();

@@ -75,8 +85,10 @@ ndk::ScopedAStatus Fingerprint::getSensorProps(std::vector<SensorProps>* out) {
    *out = {{commonProps,
             mSensorType,
             {sensorLocation},
             SUPPORTS_NAVIGATION_GESTURES,
             false /* supportsDetectInteraction */}};
             navigationGuesture,
             detectInteraction,
             displayTouch,
             controlIllumination}};
    return ndk::ScopedAStatus::ok();
}

+47 −2
Original line number Diff line number Diff line
@@ -65,7 +65,7 @@ $ adb shell cmd fingerprint sync
      $ adb shell getprop persist.vendor.fingerprint.virtual.enrollments
      ```

### Authenticate
## Authenticate

To authenticate successfully set the enrolled id that should succeed. Unset it
or change the value to make authenticate operations fail:
@@ -74,7 +74,52 @@ or change the value to make authenticate operations fail:
$ adb shell setprop vendor.fingerprint.virtual.enrollment_hit 1
````

### View HAL State
## Acquired Info Insertion

Fingerprint image acquisition states at HAL are reported to framework via onAcquired() callback. The valid acquired state info for AIDL HAL include

{UNKNOWN(0), GOOD(1), PARTIAL(2), INSUFFICIENT(3), SENSOR_DIRTY(4), TOO_SLOW(5), TOO_FAST(6), VENDOR(7), START(8), TOO_DARK(9), TOO_BRIGHT(10), IMMOBILE(11), RETRYING_CAPTURE(12)}

Refer to [AcquiredInfo.aidl](../android/hardware/biometrics/fingerprint/AcquiredInfo.aidl) for details


The states can be specified in sequence for the HAL operations involving fingerprint image captures, namely authenticate, enrollment and detectInteraction

```shell
$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_acquired 6,9,1
$ adb shell setprop vendor.fingerprint.virtual.operation_detect_interaction_acquired 6,1
$ adb shell setprop vendor.fingerprint.virtual.next_enrollment 2:1000-[5,1],500:true

#next_enrollment format example:
.---------------------- enrollment id (2)
|   .------------------ the image capture 1 duration (1000ms)
|   |   .--------------   acquired info first (TOO_SLOW)
|   |   | .------------   acquired info second (GOOD)
|   |   | |   .-------- the image capture 2 duration (500ms)
|   |   | |   |   .---- enrollment end status (success)
|   |   | |   |   |
|   |   | |   |   |
|   |   | |   |   |
2:1000-[5,1],500:true
```
For vendor specific acquired info, acquiredInfo = 1000 + vendorAcquiredInfo

## Error Insertion
The valid error codes for AIDL HAL include

{UNKNOWN(0), HW_UNAVAILABLE(1), UNABLE_TO_PROCESS(2), TIMEOUT(3), NO_SPACE(4), CANCELED(5), UNABLE_TO_REMOVE(6), VENDOR(7), BAD_CALIBRATION(8)}

Refer to [Error.aidl](../android/hardware/biometrics/fingerprint/Error.aidl) for details


There are many HAL operations which can result in errors, refer to [here](fingerprint.sysprop) file for details.

```shell
$ adb shell setprop vendor.fingerprint.virtual.operation_authenticate_error 8
```
For vendor specific error, errorCode = 1000 + vendorErrorCode

## View HAL State

To view all the properties of the HAL (see `fingerprint.sysprop` file for the API):

+70 −6
Original line number Diff line number Diff line
@@ -5,7 +5,7 @@ props {
    api_name: "authenticator_id"
    type: Long
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.authenticator_id"
    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
  }
  prop {
    api_name: "challenge"
@@ -13,6 +13,21 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.challenge"
  }
  prop {
    api_name: "control_illumination"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
  }
  prop {
    api_name: "detect_interaction"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
  }
  prop {
    api_name: "display_touch"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
  }
  prop {
    api_name: "enrollment_hit"
    type: Integer
@@ -28,7 +43,18 @@ props {
  prop {
    api_name: "lockout"
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.lockout"
    prop_name: "persist.vendor.fingerprint.virtual.lockout"
  }
  prop {
    api_name: "max_enrollments"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
  }
  prop {
    api_name: "navigation_guesture"
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
  }
  prop {
    api_name: "next_enrollment"
@@ -36,12 +62,24 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.next_enrollment"
  }
  prop {
    api_name: "operation_authenticate_acquired"
    type: String
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
  }
  prop {
    api_name: "operation_authenticate_duration"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_duration"
  }
  prop {
    api_name: "operation_authenticate_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
  }
  prop {
    api_name: "operation_authenticate_fails"
    access: ReadWrite
@@ -54,9 +92,22 @@ props {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_latency"
  }
  prop {
    api_name: "operation_detect_interaction_fails"
    api_name: "operation_detect_interaction_acquired"
    type: String
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
  }
  prop {
    api_name: "operation_detect_interaction_duration"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
  }
  prop {
    api_name: "operation_detect_interaction_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
  }
  prop {
    api_name: "operation_detect_interaction_latency"
@@ -65,9 +116,10 @@ props {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_latency"
  }
  prop {
    api_name: "operation_enroll_fails"
    api_name: "operation_enroll_error"
    type: Integer
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
  }
  prop {
    api_name: "operation_enroll_latency"
@@ -75,12 +127,24 @@ props {
    access: ReadWrite
    prop_name: "vendor.fingerprint.virtual.operation_enroll_latency"
  }
  prop {
    api_name: "sensor_id"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
  }
  prop {
    api_name: "sensor_location"
    type: String
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_location"
  }
  prop {
    api_name: "sensor_strength"
    type: Integer
    access: ReadWrite
    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
  }
  prop {
    api_name: "type"
    type: String
+125 −12
Original line number Diff line number Diff line
@@ -32,8 +32,12 @@ prop {
    api_name: "enrollment_hit"
}

# the next enrollment in the format: "<id>:<delay>,<delay>,...:<result>"
# for example: "2:0:true"
# the next enrollment in the format of:
# "<id>:<delay>,<delay>,...:<result>"
# <delay> = <duration-[acquiredInfos]>
# [acquiredInfos] = [acquiredInfo1, acquiredInfo2, ...]
# (refer to README.md file for acquiredInfo values)
# e.g. "2:100,20:true", "2:100-[5,1],20:true"
# this property is reset after enroll completes
prop {
    prop_name: "vendor.fingerprint.virtual.next_enrollment"
@@ -45,7 +49,7 @@ prop {

# value for getAuthenticatorId or 0
prop {
    prop_name: "vendor.fingerprint.virtual.authenticator_id"
    prop_name: "persist.vendor.fingerprint.virtual.authenticator_id"
    type: Long
    scope: Public
    access: ReadWrite
@@ -63,7 +67,7 @@ prop {

# if locked out
prop {
    prop_name: "vendor.fingerprint.virtual.lockout"
    prop_name: "persist.vendor.fingerprint.virtual.lockout"
    type: Boolean
    scope: Public
    access: ReadWrite
@@ -79,22 +83,26 @@ prop {
    api_name: "operation_authenticate_fails"
}

# force all detectInteraction operations to fail
# force all detectInteraction operations to error out
# error consists of errorCode and vendorErrorCode
# valid errorCodes are listed in README.md file
# vendorErrorCode = (error>1000) ? error-1000 : 0
# e.g. error(1002) --> errorCode(7) and vendorErrorCode(2)
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_fails"
    type: Boolean
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_fails"
    api_name: "operation_detect_interaction_error"
}

# force all enroll operations to fail
# force all enroll operations to result in error
prop {
    prop_name: "vendor.fingerprint.virtual.operation_enroll_fails"
    type: Boolean
    prop_name: "vendor.fingerprint.virtual.operation_enroll_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_enroll_fails"
    api_name: "operation_enroll_error"
}

# add a latency to authentication operations
@@ -134,6 +142,15 @@ prop {
    api_name: "operation_authenticate_duration"
}

# insert error for authenticate operations
prop {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_error"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_authenticate_error"
}

# sensor location
#    <x>:<y>:<radius> in pixel
prop {
@@ -143,3 +160,99 @@ prop {
    access: ReadWrite
    api_name: "sensor_location"
}

# acquired info during authentication in format of sequence
prop {
    prop_name: "vendor.fingerprint.virtual.operation_authenticate_acquired"
    type: String
    scope: Public
    access: ReadWrite
    api_name: "operation_authenticate_acquired"
}

# millisecond duration for detect interaction operations
# (waits for changes to enrollment_hit)
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_duration"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_duration"
}

# acquired info during detect interaction operation in format of sequence
# e.g. 5,6,1  (TOO_SLOW, TOO_FAST, GOOD)
# onAcquired() callback will be invoked in sequence
# vendorAcquiredCode = (acquired>1000) ? acquired-1000 : 0
prop {
    prop_name: "vendor.fingerprint.virtual.operation_detect_interaction_acquired"
    type: String
    scope: Public
    access: ReadWrite
    api_name: "operation_detect_interaction_acquired"
}

# sensor id (default: 5)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.sensor_id"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "sensor_id"
}

# sensor strength (default: 2)
# [0=CONVENECE, 1=WEAK, 2=STRONG]
prop {
    prop_name: "persist.vendor.fingerprint.virtual.sensor_strength"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "sensor_strength"
}

# max enrollments per user (default: 5)
#
prop {
    prop_name: "persist.vendor.fingerprint.virtual.max_enrollments"
    type: Integer
    scope: Public
    access: ReadWrite
    api_name: "max_enrollments"
}

# whether support navigation guestures (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.navigation_guesture"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "navigation_guesture"
}

# whether support detect interaction (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.detect_interaction"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "detect_interaction"
}

# whether support display touch by hal (default: true)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.udfps.display_touch"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "display_touch"
}

# whether support illumination control  by hal (default: false)
prop {
    prop_name: "persist.vendor.fingerprint.virtual.udfps.control_illumination"
    type: Boolean
    scope: Public
    access: ReadWrite
    api_name: "control_illumination"
}
Loading