Add a knob: an undecided press at lift is a no-match
rescan=0 made every frame terminal, which is what stopped a wrong finger from hanging the client -- but it also disabled the trustlet's own "image not good enough yet, try again" answer, so a marginal first frame became a hard rejection. In real use that showed as a quick tap of the enrolled finger answering verify-no-match: one frame, rejected. Matches land at frame 3, 5, 8 of a press; the first frame is the finger landing. The alternative is to let the trustlet keep its rescan budget and handle the wrong finger where it actually manifests, at the press level: a press that lifts with no terminal verdict is reported as no-match. The trustlet then answers -11 on marginal frames instead of rejecting them, and the press keeps going until it matches or the finger lifts. A knob rather than a decision, because the trade-off is measured, not assumed: under the stock budget seven of nineteen correct presses ended undecided at the old 500 ms frame rate, and whether the faster loop closes that gap is the question the next runs answer.
This commit is contained in:
parent
32fe0ac665
commit
93ab8570e0
1 changed files with 13 additions and 2 deletions
|
|
@ -81,6 +81,15 @@ std::string g_logDir = "/var/log/fingerprintd";
|
|||
std::string g_stateDir = "/var/lib/fingerprintd";
|
||||
int g_rescan = -1; // -1 = leave the config's value alone
|
||||
|
||||
// What a press that ends with no terminal verdict means. At the stock rescan
|
||||
// budget a wrong finger answers "not identified yet" on every frame and never
|
||||
// yields a terminal frame, so its press is undecided at lift -- and the only
|
||||
// way a client ever hears verify-no-match is to treat that as one. The cost is
|
||||
// on the correct finger: a press that ran out of frames before the matcher
|
||||
// reached a verdict is also reported as no-match. Under rescan=0 this cannot
|
||||
// arise (every frame is terminal), so the knob only matters with a budget.
|
||||
bool g_undecidedIsNoMatch = false;
|
||||
|
||||
// The namespace key the trustlet hashes into the SFS group's directory name.
|
||||
// It defaults to Android's because that is what this device's existing store
|
||||
// was written under. It does NOT isolate anything -- SET_ACTIVE_GROUP's path
|
||||
|
|
@ -1297,12 +1306,13 @@ public:
|
|||
inPress = false;
|
||||
if (pressMatched) {
|
||||
out.decided = true; out.matched = true; out.fid = pressFid;
|
||||
} else if (pressRejected) {
|
||||
} else if (pressRejected || (g_undecidedIsNoMatch && pressFrames > 0)) {
|
||||
out.decided = true; out.matched = false;
|
||||
}
|
||||
std::println(" press {}: {} frames, {} rescans -> {}", out.presses, pressFrames,
|
||||
rescans, pressMatched ? std::format("MATCH fid={}", pressFid)
|
||||
: pressRejected ? "NO MATCH" : "undecided");
|
||||
: pressRejected ? "NO MATCH"
|
||||
: out.decided ? "NO MATCH (undecided at lift)" : "undecided");
|
||||
}
|
||||
}
|
||||
if (finger) pressFrames++;
|
||||
|
|
@ -2060,6 +2070,7 @@ int main(int argc, char** argv) {
|
|||
if (a == "--cal-save") { doCalSave = true; probe = true; g_verbose = true; }
|
||||
if (a.starts_with("--frames=")) frames = std::stoi(std::string(a.substr(9)));
|
||||
if (a.starts_with("--frame-gap=")) g_frameGapMs = std::stoi(std::string(a.substr(12)));
|
||||
if (a == "--undecided=nomatch") g_undecidedIsNoMatch = true;
|
||||
if (a.starts_with("--log-dir=")) g_logDir = a.substr(10);
|
||||
if (a.starts_with("--state-dir=")) g_stateDir = a.substr(12);
|
||||
if (a.starts_with("--rescan=")) g_rescan = std::stoi(std::string(a.substr(9)));
|
||||
|
|
|
|||
Loading…
Reference in a new issue