Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each, while a never-enrolled finger progressed normally. Re-enrolment adds a template and there is no trustlet-side remove, so a measured finger's old template has to go before it can be enrolled again. wipe does that the way it has been done by hand twice: backup first, daemon stopped so the trustlet reloads from the store, only the template containers removed, the group index kept because deleting it risks the RPMB anti-rollback counters going stale, the name map cleared, then a restart and the sizes. enrol checks the name map and refuses a finger that is already there, pointing at wipe, so the refusal cannot be mistaken for bad pressing again.
145 lines
6.2 KiB
Shell
Executable file
145 lines
6.2 KiB
Shell
Executable file
#!/bin/sh
|
|
# fplearn.sh -- the template-learning measurement, as a protocol rather than a
|
|
# pile of remembered commands.
|
|
#
|
|
# fplearn.sh wipe remove every stored template (backup first)
|
|
# fplearn.sh enrol [finger] enrol at the config's sample count
|
|
# fplearn.sh base [n] [w] trial with learning OFF (the baseline)
|
|
# fplearn.sh trend [n] [w] three trials with learning ON
|
|
# fplearn.sh sizes just print the template container sizes
|
|
#
|
|
# WIPE FIRST when re-enrolling a finger that is already in the group. Measured
|
|
# 2026-09-04: the duplicated-finger check refuses a finger the group already
|
|
# holds -- 0 accepted of 7 presses, rc=0 on every one, while a never-enrolled
|
|
# finger progressed normally. Re-enrolment ADDS a template and there is no
|
|
# trustlet-side remove, so the old one has to go first. `enrol` refuses a
|
|
# finger name that is already in the map and points here.
|
|
#
|
|
# WHY IT IS SHAPED LIKE THIS. Learning is cumulative: every matched press folds
|
|
# frames into the stored template, so a second run is not a repeat of the first
|
|
# and an A/B against a moving template is not an A/B at all. The only honest
|
|
# comparison is on ONE template lineage, in order:
|
|
#
|
|
# 1. enrol a fresh template, 20 samples, no position prompts --
|
|
# which is also the outstanding replication of the 7/10
|
|
# result, the one measurement this lane was parked on
|
|
# 2. base learning off: the clean number for THIS template, and
|
|
# the only figure comparable to every rate in the journal
|
|
# 3. trend learning on, three times: the rate should climb, and
|
|
# the container size is an independent witness that it
|
|
# is the template moving and not the weather
|
|
#
|
|
# Do NOT read run 1 of the trend as "learning made it better". Run 1 starts on
|
|
# the same template the baseline ended on; it is the first run that can improve
|
|
# it, not one that has already been improved.
|
|
set -u
|
|
|
|
GROUP=/mnt/persist/data/RIY7A+mQm3EA4FsCUmkJo0b9dFUYP2YZ4P5hmMiZgeA_Alt
|
|
MAP=/var/lib/fingerprintd/fingers-10000.map
|
|
UNIT=fingerprintd-test
|
|
BIN=/tmp/fingerprintd
|
|
COMMON="--daemon --verbose --edge-wake --sfs-root=/var/lib/fingerprintd/sfs --sfs-writable --rpmb-write"
|
|
|
|
sizes() {
|
|
# A template is stored twice, the container and its backup, so the sizes
|
|
# come in pairs. The BODY is the container minus its 4096-byte header.
|
|
sudo ls -la "$GROUP" 2>/dev/null | awk '$5 > 200000 { printf " %9d body %9d %s\n", $5, $5-4096, $9 }' | sort -u
|
|
}
|
|
|
|
restart() { # $1 = extra args
|
|
sudo systemctl stop "$UNIT" 2>/dev/null
|
|
sleep 2
|
|
sudo systemd-run --unit="$UNIT" --collect $BIN $COMMON $1 >/dev/null 2>&1
|
|
printf 'daemon starting'
|
|
i=0
|
|
while [ $i -lt 40 ]; do
|
|
if busctl --system list 2>/dev/null | grep -q net.reactivated.Fprint; then
|
|
# Owning the name is not the same as being ready: the session comes
|
|
# up on the worker thread afterwards.
|
|
sleep 6; printf ' ready\n'; return 0
|
|
fi
|
|
printf '.'; sleep 1; i=$((i+1))
|
|
done
|
|
printf ' TIMED OUT\n'; return 1
|
|
}
|
|
|
|
case "${1:-}" in
|
|
sizes)
|
|
echo "template containers now:"; sizes ;;
|
|
|
|
wipe)
|
|
# The procedure of 2026-09-03 and 2026-09-04, and its reasoning: ONLY the
|
|
# template containers go (>200000 bytes; each template is stored twice).
|
|
# The 1588-byte group index is KEPT -- deleting it risks the RPMB
|
|
# anti-rollback counters going stale against object ids QTEE would then
|
|
# recreate, which already cost an index restore once -- and a missing
|
|
# template container is the known-good "not exist, skip" case. The daemon
|
|
# is stopped first so the trustlet reloads from the store, and a backup is
|
|
# taken first because a template is not reproducible without a finger.
|
|
echo "=== wipe: every stored template ==="
|
|
echo "before:"; sizes
|
|
D=$HOME/fp6-backups/$(date +%Y-%m-%d-%H%M)-pre-wipe
|
|
mkdir -p "$D"
|
|
sudo tar -cf "$D/persist-data.tar" -C /mnt/persist data
|
|
sudo cp "$MAP" "$D/" 2>/dev/null || true
|
|
sudo chown -R "$(id -u):$(id -g)" "$D"
|
|
echo "backup: $D ($(tar -tf "$D/persist-data.tar" | wc -l) entries, $(sha256sum "$D/persist-data.tar" | cut -c1-16))"
|
|
sudo systemctl stop "$UNIT" 2>/dev/null; sleep 2
|
|
n=0
|
|
for f in $(sudo ls "$GROUP"); do
|
|
sz=$(sudo stat -c %s "$GROUP/$f")
|
|
if [ "$sz" -gt 200000 ]; then sudo rm -f "$GROUP/$f"; n=$((n+1)); fi
|
|
done
|
|
sudo sync
|
|
sudo sh -c ": > $MAP"
|
|
echo "removed $n container(s); index and small containers kept; map cleared"
|
|
restart "--learn=1" || exit 1
|
|
fprintd-list user 2>&1 | tail -1
|
|
echo "after:"; sizes
|
|
echo; echo "next: fplearn.sh enrol <finger>" ;;
|
|
|
|
enrol)
|
|
F=${2:-right-middle-finger}
|
|
if sudo grep -q "^$F " "$MAP" 2>/dev/null; then
|
|
echo "$F is already enrolled (in $MAP)."
|
|
echo "The trustlet REFUSES to re-enrol a finger it already holds; run"
|
|
echo " fplearn.sh wipe"
|
|
echo "first. (Measured 2026-09-04: 0 accepted of 7 presses, rc=0 each.)"
|
|
exit 1
|
|
fi
|
|
echo "=== enrol $F ==="
|
|
echo "sizes before:"; sizes
|
|
restart "--learn=1" || exit 1
|
|
/tmp/fpenrol.sh "$F"
|
|
echo; echo "sizes after the enrolment:"; sizes
|
|
echo; echo "next: fplearn.sh base" ;;
|
|
|
|
base)
|
|
N=${2:-10}; W=${3:-5}
|
|
echo "=== BASELINE: learning OFF ==="
|
|
restart "--learn=0" || exit 1
|
|
echo "sizes before:"; sizes
|
|
/tmp/fptrial.sh "$N" "$W"
|
|
echo; echo "sizes after (MUST be unchanged -- learning was off):"; sizes
|
|
echo; echo "next: fplearn.sh trend" ;;
|
|
|
|
trend)
|
|
N=${2:-10}; W=${3:-5}
|
|
echo "=== TREND: learning ON, three runs on one template ==="
|
|
restart "--learn=1" || exit 1
|
|
echo "sizes at the start:"; sizes
|
|
r=1
|
|
while [ $r -le 3 ]; do
|
|
echo; echo "----- learning run $r of 3 -----"
|
|
/tmp/fptrial.sh "$N" "$W"
|
|
echo "sizes after run $r:"; sizes
|
|
r=$((r+1))
|
|
done
|
|
echo
|
|
echo "Read it as a trend, not three numbers. A rate that climbs while the"
|
|
echo "container grows is learning; a rate that moves while the container"
|
|
echo "does not is noise, and the daemon's own 'learn:' lines say which." ;;
|
|
|
|
*)
|
|
sed -n '2,38p' "$0"; exit 1 ;;
|
|
esac
|