feat: parental control - a daily play time budget - #809
Draft
dalexanco wants to merge 3 commits into
Draft
Conversation
dalexanco
force-pushed
the
feat/parental-control
branch
2 times, most recently
from
August 16, 2026 23:22
606d10c to
7c7466a
Compare
Author
|
note : exempt is usefull for shortcut pak to avoid making it blocked since it use rom pak type |
Adds Parental.pak, an optional cap on how long the device can be played each day. Set a limit (90 minutes by default); while time is left nothing changes. Once it is spent, a running game is warned, then stopped, and further rom launches are refused until the next day. The settings screen sits behind a button-sequence code (UP UP DOWN DOWN by default). This is a household guardrail, not a lock. Anyone who can edit the SD card can lift it, and every path fails open: a missing binary, a zero limit or an unreadable db all let the game start. Implementation -------------- All of the policy lives in the pak. The firmware only gained three small generic capabilities, each useful on its own: - Hooks. A synchronous pre-launch hook (*.sync.sh) that exits non-zero now cancels the launch: run_hooks.sh propagates the failure and MinUI.pak guards the launch with it. Background hooks keep the old behaviour -- their exit status is not recoverable from `wait` in POSIX sh, so only .sync.sh hooks get a vote. - minarch. SIGUSR1 saves and quits; SIGUSR2 shows the message left in NOTIFY_PATH over the running game as a NOTIFICATION_SYSTEM toast. The handlers only raise a flag -- the work happens on the main thread once per frame, since neither Menu_beforeSleep() nor Notification_push() is async-signal-safe. - gametimedb. play_activity_get_play_time_since() sums the seconds played across every rom since a given epoch, the session in progress included. Parental.pak composes the three. `parental.elf --gate` answers the pre-launch hook, exit 1 refusing the launch; `--watch` is backgrounded alongside the game and polls every 10s to warn, then stop it; `--stop` tears the watcher down from the post-launch hook. The budget is recomputed from gametimedb on every check rather than stored, so the daily reset is implicit and there is no counter to keep in sync. Opening the pak once is what arms it -- that is when its hooks are installed into .hooks/. Only rom launches are gated. Paks are left alone, both because they open no play session to measure and because blocking them would lock the owner out of the settings screen. Some launchers make a pak look like a rom, though -- a bridge emulator that execs a tool is indistinguishable from a real emulator at this level, since HOOK_TYPE describes the shape of the launch and not the nature of what is launched. The settings screen therefore lists the installed emulators and lets the owner exempt any of them from the budget. Only the exemptions are persisted, never the list of emulators found. A stored list would be a snapshot, and anything installed afterwards would fall outside it and run unmetered; asking instead whether a pak is explicitly exempted keeps the unknown case closed.
Adds a track+fill bar under "X left today" on the home screen, filled proportionally to remaining/limit. Confirmed and documented that the bar doesn't move just from having the screen open: opening a Tools pak never writes to the play-time DB the remaining-time calc reads from (only real rom launches do, via gametimectl.elf start).
Adds an "Extra time" entry next to Daily limit: same hours/minutes editor, but the amount only counts for the calendar day it was granted on (extra_day tracks which day, so it stops applying once the day rolls over, no reset job needed). Folded into remainingFrom() so the gate/watch enforcement and the home screen (including the progress bar's fraction) all pick it up automatically.
dalexanco
force-pushed
the
feat/parental-control
branch
from
August 17, 2026 20:56
7c7466a to
00f9fad
Compare
Member
|
A couple of comments here. It is still marked as draft so I'm assuming you are still working on it, but allow be to leave a few notes:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a Parental.pak — a daily play-time budget for the console, with a
button-code-locked settings screen so a child can't just turn it off.
feat(parental): daily play time budget
Description (for parents)
Parental.pak lets you cap how long the console can be played each day.
time already played.
menu, where you can:
a "study" emulator or app always available). Everything is blocked by
default; only what you explicitly allow is exempt.
today" and refuses to start. While playing, the console warns "Stopping in
5 min" shortly before time runs out, then stops the game after a 3-second
on-screen notice — so a child isn't cut off with zero warning mid-session.
logged as play activity, from midnight (local time) onward.
Technical description
New files
workspace/all/parental/parental.c(+makefile) — single binary,built for
tg5040/tg5050, four modes selected by argv:exemptions, change code), limit editor, exemption list, new-code capture.
--gate— invoked synchronously from the pre-launch hook; exits 1 toveto the launch when the daily budget is exhausted, 0 otherwise.
--watch— backgrounded by the gate hook after a launch is allowed;polls every
WATCH_INTERVAL_SEC(10s), warns viaNOTIFY_PATH+SIGUSR2tominarch.elfatwarn_minutesremaining, and force-stopsthe game (
SIGUSR2notice, 3s pause,SIGUSR1) when the budget hits 0.Also self-terminates if
minarch.elfisn't running anymore (safety netin case the post-launch hook didn't fire).
--stop— invoked from the post-launch hook; kills the--watchprocess via its PID file (
/tmp/parental.pid).skeleton/EXTRAS/Tools/{tg5040,tg5050}/Parental.pak/launch.sh— on open,(re)installs the two hook scripts below into
$HOOKS_PATH/{pre-launch,post-launch}.d/, then launches the settings UI.This is the only moment a Tools pak runs, so opening it once is what arms
enforcement.
.../Parental.pak/hooks/parental-gate.sync.sh— pre-launch hook (mustkeep the
.sync.shsuffix: only synchronous pre-launch hooks can veto alaunch via non-zero exit). No-ops for non-ROM hook invocations. Resolves
the launching pak's name from
HOOK_EMU_PATH's parent directory (notbasename, which would just belaunch.shfor every emulator) and skipsenforcement if that pak is in the exemption list. Otherwise calls
parental.elf --gate; on refusal it closes the already-openedplay_activityrow viagametimectl.elf stop_all(so a refused launchdoesn't count as played time) and shows a
show2.elftoast..../Parental.pak/hooks/parental-stop.sh— post-launch hook, tears downthe watcher via
parental.elf --stop.Config storage —
$SHARED_USERDATA_PATH/parental.txt, plainkey=valuelines:limit_minutes <= 0disables the whole feature (gate always allows).warn_minutesisn't exposed in the UI, only editable by hand.snapshot of installed emulators — anything installed later stays blocked
by default, matched as a whole comma-separated token (so
GB.pakcan'tmatch inside
GBA.pak).code_hash/code_len), not storedin the clear. This is explicitly not a security boundary against a
motivated attacker — the threat model is a child poking around with
Files.pak, not an adversary — it just keeps the code from being readable
at a glance. Default code is
UP, UP, DOWN, DOWN.Play time accounting — no new tracking is introduced. Time played is
aggregated per-day from the existing
gametimedb/play_activitysqlitetable via
play_activity_get_play_time_since(start_of_today), so it staysconsistent with whatever the console already records as a play session.
UI — plain SDL2 + the shared
GFX_*/pill-list widgets used elsewherein NextUI tools, consistent with the rest of the launcher's look
(
GFX_blitPill,GFX_blitButtonGroup,GFX_blitHardwareHints, etc.). Codeentry is a configurable-length sequence over a fixed button set (
UP DOWN LEFT RIGHT A X Y L1 R1 SELECT);Balways means "back" and is deliberatelyexcluded from the code alphabet so no confirm key is needed, and
STARTterminates capture when setting a new code.