mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:07:04 +01:00
Location/curfew goes to daemon_location.sh, the derived state files to daemon_state.sh, the app layer to daemon_apps.sh. All 23 functions moved verbatim -- nothing restructured, which matters more here than anywhere else in this session. focus_daemon.sh has five `while IFS= read -r pkg; do ... done <file` loops and EVERY body calls pm. Piping any of them in lets pm inherit and drain the loop's stdin, so it would process one package instead of all of them -- measured elsewhere in this repo as 1 of 54. That audit ran BEFORE the extraction, not after coverage came back short, and all five moved untouched with a note above them saying why. CURRENT_MODE and _CURFEW_TICK_CACHED are each written in both the entry script and a library, so both stay declared with main, same call as NET_BUILT in the curfew split. 110 assertions and 33 mutations, all killed. Two survived the first run and both were defects in my own tests: the whitelist and sysprotect exactness checks used a SUPERSTRING of a listed entry, which fails under grep -qF and grep -qxF alike and so proved nothing about which was in use. Two subjects are NOT at 100%, and the numbers are reported as measured: daemon_state.sh 67/67 = 100.00% daemon_location.sh 26/40 = 65.00% daemon_apps.sh 71/76 = 93.42% Both shortfalls are kcov attribution failures, shown to be artifacts rather than gaps. daemon_location.sh's missing lines are all inside the embedded awk Haversine; mutating the Earth radius and dropping the longitude term both fail the suite, and an isolated probe shows a one-line awk measuring 100% where the identical multi-line one measures 0%. Collapsing the formula to satisfy the tool would cost the readability of the only real mathematics in the repo, so it stays. daemon_apps.sh's five are the trailing `done <file` of the very loops described above. That is the same artifact piping fixed in curfew_net.sh, and it is exactly what must NOT be done here. Redirecting two of them from /dev/null fails the suite, so the lines run; all three are pinned in the mutation spec instead. Over-cap count 19 -> 18. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
207 lines
5.2 KiB
Bash
Executable File
207 lines
5.2 KiB
Bash
Executable File
#!/system/bin/sh
|
|
# shellcheck shell=ash
|
|
# ============================================================
|
|
# Focus Mode Daemon
|
|
# Runs on rooted Android device. Periodically checks GPS
|
|
# location and restricts non-whitelisted apps when near home.
|
|
# ============================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
. "$SCRIPT_DIR/config.sh"
|
|
# shellcheck source=daemon_location.sh
|
|
. "$SCRIPT_DIR/daemon_location.sh"
|
|
# shellcheck source=daemon_state.sh
|
|
. "$SCRIPT_DIR/daemon_state.sh"
|
|
# shellcheck source=daemon_apps.sh
|
|
. "$SCRIPT_DIR/daemon_apps.sh"
|
|
|
|
PIDFILE="$STATE_DIR/daemon.pid"
|
|
|
|
# ---- PID lock: exit if already running ----
|
|
acquire_lock() {
|
|
mkdir -p "$STATE_DIR"
|
|
if [ -f "$PIDFILE" ]; then
|
|
local old_pid
|
|
old_pid="$(cat "$PIDFILE")"
|
|
if kill -0 "$old_pid" 2>/dev/null; then
|
|
# Verify the PID is actually a focus_daemon, not a reused PID
|
|
local cmdline
|
|
cmdline="$(tr '\0' ' ' <"/proc/$old_pid/cmdline" 2>/dev/null)"
|
|
if echo "$cmdline" | grep -q "focus_daemon"; then
|
|
echo "Daemon already running (PID $old_pid), exiting."
|
|
exit 0
|
|
fi
|
|
fi
|
|
# Stale or reused pidfile
|
|
rm -f "$PIDFILE"
|
|
fi
|
|
echo $$ >"$PIDFILE"
|
|
}
|
|
|
|
# ---- Logging ----
|
|
log() {
|
|
local ts
|
|
ts="$(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "[$ts] $1" >>"$LOG_FILE"
|
|
}
|
|
|
|
rotate_log() {
|
|
local lines
|
|
lines="$(wc -l <"$LOG_FILE" 2>/dev/null || echo 0)"
|
|
if [ "$lines" -gt "$LOG_MAX_LINES" ]; then
|
|
local tmp="$LOG_FILE.tmp"
|
|
tail -n "$LOG_MAX_LINES" "$LOG_FILE" >"$tmp"
|
|
mv "$tmp" "$LOG_FILE"
|
|
fi
|
|
}
|
|
|
|
# ---- Build helper files for fast package checks ----
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---- Initialization ----
|
|
init() {
|
|
mkdir -p "$STATE_DIR"
|
|
touch "$LOG_FILE"
|
|
touch "$DISABLED_APPS_FILE"
|
|
# Ensure state files are writable (survives reboot / permission drift)
|
|
chmod 666 "$LOG_FILE" "$DISABLED_APPS_FILE" "$PIDFILE" 2>/dev/null
|
|
# Status file must be world-readable (companion app reads it).
|
|
# State dir must be world-writable+executable so the companion app can
|
|
# drop the recheck trigger file (it runs as a normal app UID).
|
|
chmod 777 "$STATE_DIR" 2>/dev/null
|
|
|
|
if [ "$HOME_LAT" = "0.000000" ] && [ "$HOME_LON" = "0.000000" ]; then
|
|
log "ERROR: Home coordinates not set! Edit config_secrets.sh first."
|
|
exit 1
|
|
fi
|
|
|
|
if ! echo "$HOME_LAT" | grep -Eq '^[-]?[0-9]+(\.[0-9]+)?$'; then
|
|
log "ERROR: HOME_LAT is invalid ('$HOME_LAT'). Expected decimal degrees in config_secrets.sh"
|
|
exit 1
|
|
fi
|
|
|
|
if ! echo "$HOME_LON" | grep -Eq '^[-]?[0-9]+(\.[0-9]+)?$'; then
|
|
log "ERROR: HOME_LON is invalid ('$HOME_LON'). Expected decimal degrees in config_secrets.sh"
|
|
exit 1
|
|
fi
|
|
|
|
build_whitelist_file
|
|
build_night_whitelist_file
|
|
build_sysprotect_file
|
|
build_blocked_sys_file
|
|
refresh_default_handlers
|
|
rotate_log
|
|
|
|
if [ -f "$MODE_FILE" ]; then
|
|
CURRENT_MODE="$(cat "$MODE_FILE")"
|
|
else
|
|
CURRENT_MODE="normal"
|
|
fi
|
|
|
|
if [ "$CURRENT_MODE" = "focus" ]; then
|
|
reconcile_disabled_apps
|
|
fi
|
|
|
|
log "Focus mode daemon started (PID=$$, mode=$CURRENT_MODE, home=$HOME_LAT,$HOME_LON, radius=${RADIUS}m)"
|
|
log "Intervals: focus=${CHECK_INTERVAL_FOCUS}s normal=${CHECK_INTERVAL_NORMAL}s"
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---- Focus Mode Control ----
|
|
|
|
|
|
|
|
|
|
# ---- Sleep with early-wake on recheck trigger ----
|
|
# Polls for $RECHECK_TRIGGER every second; if found, consumes it and returns
|
|
# early. The file can be touched by the companion app (via "Re-check now"
|
|
# button) or by `focus_ctl.sh recheck` from a shell.
|
|
sleep_with_recheck() {
|
|
local total="$1"
|
|
local elapsed=0
|
|
while [ "$elapsed" -lt "$total" ]; do
|
|
if [ -e "$RECHECK_TRIGGER" ]; then
|
|
rm -f "$RECHECK_TRIGGER" 2>/dev/null
|
|
log "Manual re-check triggered"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
elapsed=$((elapsed + 1))
|
|
done
|
|
}
|
|
|
|
# ---- Signal handlers ----
|
|
cleanup() {
|
|
log "Daemon shutting down - re-enabling all apps"
|
|
disable_focus_mode
|
|
rm -f "$PIDFILE"
|
|
exit 0
|
|
}
|
|
|
|
# HUP is intentionally NOT trapped so the daemon survives ADB disconnects.
|
|
# Only SIGTERM/SIGINT trigger a clean shutdown.
|
|
trap cleanup INT TERM
|
|
|
|
# ---- Main Loop ----
|
|
main() {
|
|
acquire_lock
|
|
init
|
|
|
|
while true; do
|
|
# Invalidate the per-tick curfew_active() memo (see its definition).
|
|
_CURFEW_TICK_CACHED=""
|
|
|
|
location="$(get_location)"
|
|
|
|
if [ -n "$location" ]; then
|
|
lat="$(echo "$location" | cut -d',' -f1)"
|
|
lon="$(echo "$location" | cut -d',' -f2)"
|
|
distance="$(calc_distance "$lat" "$lon" "$HOME_LAT" "$HOME_LON")"
|
|
|
|
if [ "$CURRENT_MODE" = "focus" ]; then
|
|
threshold=$((RADIUS + HYSTERESIS))
|
|
else
|
|
threshold=$((RADIUS - HYSTERESIS))
|
|
fi
|
|
|
|
if [ "$distance" -le "$threshold" ] 2>/dev/null; then
|
|
enable_focus_mode
|
|
else
|
|
disable_focus_mode
|
|
fi
|
|
|
|
curfew_state="day"
|
|
curfew_active && curfew_state="CURFEW"
|
|
log "Location: $lat,$lon | Distance: ${distance}m | Threshold: ${threshold}m | Mode: $CURRENT_MODE | Curfew: $curfew_state"
|
|
write_status_snapshot "$CURRENT_MODE" "$lat" "$lon" "$distance" "$threshold"
|
|
else
|
|
log "Location unavailable - defaulting to focus mode (restrictions ON)"
|
|
enable_focus_mode
|
|
write_status_snapshot "$CURRENT_MODE" "" "" "null" "null"
|
|
fi
|
|
|
|
# Dynamic interval: shorter at home (can charge), longer away (save battery).
|
|
# sleep_with_recheck returns early if the companion app requests a recheck.
|
|
if [ "$CURRENT_MODE" = "focus" ]; then
|
|
sleep_with_recheck "$CHECK_INTERVAL_FOCUS"
|
|
else
|
|
sleep_with_recheck "$CHECK_INTERVAL_NORMAL"
|
|
fi
|
|
|
|
rotate_log
|
|
done
|
|
}
|
|
|
|
main "$@"
|