diff --git a/implementations/main.cpp b/implementations/main.cpp index 36285c1..46a4716 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -1206,8 +1206,25 @@ public: // Select a group and count what loads. A template reload needs the init // chain to have run first -- Start() guarantees that. - int SetActiveGroup(std::uint32_t gid) { + // Selecting a group makes the trustlet RELOAD every template in it from + // storage, and on this device that is 651276 bytes crossing the listener in + // chunks -- about a megabyte of round trips per call. Measured 2026-09-05: + // ten verifications cost eleven reloads and 26 MB, all of it before the + // verify loop even starts, so all of it lands in the latency the user sees + // while being invisible to the daemon's own timing. + // + // It is also unnecessary. The trustlet holds templates in memory once + // loaded -- a successful authentication on stock produces no storage + // callbacks at all -- so a group that is already active does not need + // selecting again. `force` is for the cases that genuinely change the + // store: an enrolment, or a template removed underneath us. + int SetActiveGroup(std::uint32_t gid, bool force = false) { namespace ta = fingerprintd::ta; + if (!force && gid == gid_ && templatesLoaded_ >= 0) { + std::println("SET_ACTIVE_GROUP gid={} skipped (already active, {} template(s))", + gid, templatesLoaded_); + return templatesLoaded_; + } auto sag = ta::BuildSetActiveGroup(gid, g_groupPath); std::println("SET_ACTIVE_GROUP gid={}", gid); auto g = SendCommand(app_, ta::Cmd::SetActiveGroup, sag); @@ -1216,7 +1233,8 @@ public: Report(ta::Cmd::Enumerate, e); std::println(" templates loaded: {}", e.rc); gid_ = gid; - return e.invoked ? e.rc : -1; + templatesLoaded_ = e.invoked ? e.rc : -1; + return templatesLoaded_; } // ---- Enrolment @@ -1244,7 +1262,8 @@ public: out.why = "store is read-only or RPMB writes disabled"; return out; } - if (gid != gid_) SetActiveGroup(gid); + // An enrolment adds a template, so this one reloads for real. + SetActiveGroup(gid, /*force*/ true); // Stock's opening sequence. AUTHENTICATE is what arms the capture // session; CANCEL and RESET_LOCKOUT bracket it. @@ -1755,6 +1774,9 @@ private: Sensor sensor_; fingerprintd::engine::Baseline baseline_; std::uint32_t gid_ = 0xFFFFFFFF; + // What the last real SET_ACTIVE_GROUP reported, so a repeat claim can be + // answered without making the trustlet re-read the store. -1 = unknown. + int templatesLoaded_ = -1; // Set when a fold succeeded; cleared by the save. bool templateDirty_ = false; // Frames folded during the verify loop itself, carried into the harvest so