mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 20:27:02 +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
166 lines
6.0 KiB
Bash
Executable File
166 lines
6.0 KiB
Bash
Executable File
#!/system/bin/sh
|
|
# shellcheck shell=ash
|
|
# daemon_apps.sh — the app layer of focus_daemon.sh: deciding whether a
|
|
# package is allowed, disabling everything that is not while focus mode is on,
|
|
# and re-enabling it afterwards.
|
|
#
|
|
# A flat sibling, not lib/: deploy.sh pushes phone scripts into one directory.
|
|
#
|
|
# Sourced by focus_daemon.sh, which owns log(), $CURRENT_MODE (written here
|
|
# and in init, read by main, so it stays with them) and the config.sh globals
|
|
# these read ($DISABLED_APPS_FILE, $MODE_FILE, $STATE_DIR).
|
|
#
|
|
# NOTE for anyone editing the `while IFS= read -r pkg; do ... done <file`
|
|
# loops below: they must stay redirect-driven. Every body calls pm, which
|
|
# inherits and drains the loop's stdin if the file is piped in instead — the
|
|
# measured symptom elsewhere in this repo was processing 1 package of 54.
|
|
|
|
reconcile_disabled_apps() {
|
|
[ -f "$DISABLED_APPS_FILE" ] || return
|
|
|
|
local tmp_disabled="$STATE_DIR/disabled_by_focus.tmp"
|
|
: >"$tmp_disabled"
|
|
|
|
while IFS= read -r pkg; do
|
|
[ -z "$pkg" ] && continue
|
|
|
|
if is_allowed "$pkg"; then
|
|
pm install-existing --user 0 "$pkg" >/dev/null 2>&1 || true
|
|
pm enable "$pkg" >/dev/null 2>&1 || true
|
|
log "Re-enabled allowed app during state reconciliation: $pkg"
|
|
continue
|
|
fi
|
|
|
|
echo "$pkg" >>"$tmp_disabled"
|
|
done <"$DISABLED_APPS_FILE"
|
|
|
|
mv "$tmp_disabled" "$DISABLED_APPS_FILE"
|
|
}
|
|
|
|
# ---- Check if package is allowed (whitelist or system-protected) ----
|
|
is_allowed() {
|
|
local pkg="$1"
|
|
# During the night curfew, swap the permissive day list for the strict
|
|
# night list. The sysprotect + default-handler guards below still apply on
|
|
# top of whichever list is active.
|
|
local list="$STATE_DIR/whitelist.txt"
|
|
if curfew_active; then
|
|
list="$STATE_DIR/night_whitelist.txt"
|
|
fi
|
|
# Exact match against the active whitelist file
|
|
if grep -qxF "$pkg" "$list" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
# Prefix match against system-protect file
|
|
while IFS= read -r prefix; do
|
|
[ -z "$prefix" ] && continue
|
|
case "$pkg" in
|
|
"$prefix"*) return 0 ;;
|
|
esac
|
|
done <"$STATE_DIR/sysprotect.txt"
|
|
# Hard-stop guard: refuse to disable any package that is the current
|
|
# default handler for a critical role (Dialer / SMS / Home / Contacts).
|
|
# Without this, a misconfigured WHITELIST can disable the default Phone
|
|
# app and Android falls back to com.android.settings/.FallbackHome -
|
|
# the persistent "Phone is starting..." screen with broken SystemUI
|
|
# gestures (no swipe-up recents). Recovering requires `pm enable` over
|
|
# ADB. Treat the guard as last-resort safety net independent of WHITELIST
|
|
# contents so a future config edit can never wipe these out.
|
|
is_default_handler "$pkg" && return 0
|
|
# The default browser is guarded only OUTSIDE curfew. At night the whole
|
|
# point is to disable browsers, so this guard must not re-allow it.
|
|
if ! curfew_active &&
|
|
grep -qxF "$pkg" "$STATE_DIR/default_browser.txt" 2>/dev/null; then
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
enable_focus_mode() {
|
|
local first_entry=0
|
|
if [ "$CURRENT_MODE" != "focus" ]; then
|
|
first_entry=1
|
|
log "ENABLING focus mode - restricting non-whitelisted apps"
|
|
: >"$DISABLED_APPS_FILE"
|
|
fi
|
|
|
|
# Refresh default-handler list every tick. The user may switch dialer /
|
|
# SMS / launcher between sweeps; the guard in is_allowed() consults this
|
|
# list so a newly-promoted handler is never disabled.
|
|
refresh_default_handlers
|
|
|
|
# Blocked system app list is static; built once in init() (see
|
|
# build_blocked_sys_file), not rebuilt on every sweep.
|
|
local blocked_sys="$STATE_DIR/blocked_sys.txt"
|
|
|
|
# Periodic rescan catches third-party apps the user re-enabled (e.g. via
|
|
# Play Store or `pm enable` in a terminal) since the last tick.
|
|
# -e = enabled only, so we skip apps that are already disabled.
|
|
local tmp_pkgs="$STATE_DIR/pkg_list.txt"
|
|
pm list packages -3 -e 2>/dev/null | sed 's/^package://' >"$tmp_pkgs"
|
|
local newly_disabled=0
|
|
while IFS= read -r pkg; do
|
|
[ -z "$pkg" ] && continue
|
|
is_allowed "$pkg" && continue
|
|
if pm disable-user --user 0 "$pkg" >/dev/null 2>&1; then
|
|
grep -qxF "$pkg" "$DISABLED_APPS_FILE" 2>/dev/null ||
|
|
echo "$pkg" >>"$DISABLED_APPS_FILE"
|
|
newly_disabled=$((newly_disabled + 1))
|
|
fi
|
|
done <"$tmp_pkgs"
|
|
rm -f "$tmp_pkgs"
|
|
|
|
# Disable-for-user-0 any blocked system apps (Play Store, browsers,
|
|
# package installer UI, terminal apps).
|
|
# IMPORTANT: We intentionally use pm disable-user (NOT pm uninstall) here.
|
|
# pm uninstall -k --user 0 removes the package from Android's user-0
|
|
# package registry. If the daemon is killed with SIGKILL during a reboot
|
|
# (bypassing the cleanup trap), those packages stay uninstalled across the
|
|
# reboot. Android's bootloop-protection (MTK and others) then detects
|
|
# missing critical system packages and triggers recovery / factory wipe.
|
|
# pm disable-user leaves the package registered but inactive, so the
|
|
# PackageManager scan at next boot succeeds and no wipe occurs.
|
|
while IFS= read -r pkg; do
|
|
[ -z "$pkg" ] && continue
|
|
if pm disable-user --user 0 "$pkg" >/dev/null 2>&1; then
|
|
grep -qxF "$pkg" "$DISABLED_APPS_FILE" 2>/dev/null ||
|
|
echo "$pkg" >>"$DISABLED_APPS_FILE"
|
|
newly_disabled=$((newly_disabled + 1))
|
|
fi
|
|
done <"$blocked_sys"
|
|
|
|
CURRENT_MODE="focus"
|
|
echo "focus" >"$MODE_FILE"
|
|
|
|
if [ "$first_entry" -eq 1 ]; then
|
|
local count
|
|
count=$(wc -l <"$DISABLED_APPS_FILE" 2>/dev/null || echo 0)
|
|
log "Focus mode enabled - disabled $count apps"
|
|
elif [ "$newly_disabled" -gt 0 ]; then
|
|
log "Focus mode re-sweep: re-disabled $newly_disabled apps (re-enabled by user?)"
|
|
fi
|
|
|
|
reconcile_disabled_apps
|
|
}
|
|
|
|
disable_focus_mode() {
|
|
[ "$CURRENT_MODE" = "normal" ] && return
|
|
log "DISABLING focus mode - re-enabling apps"
|
|
|
|
local count=0
|
|
if [ -f "$DISABLED_APPS_FILE" ] && [ -s "$DISABLED_APPS_FILE" ]; then
|
|
# Re-enable all disabled apps (both 3rd-party and system apps).
|
|
# Both paths now use pm disable-user, so pm enable is the only
|
|
# restore command needed.
|
|
while IFS= read -r pkg; do
|
|
[ -z "$pkg" ] && continue
|
|
pm enable "$pkg" >/dev/null 2>&1 && count=$((count + 1))
|
|
done <"$DISABLED_APPS_FILE"
|
|
: >"$DISABLED_APPS_FILE"
|
|
fi
|
|
|
|
CURRENT_MODE="normal"
|
|
echo "normal" >"$MODE_FILE"
|
|
log "Focus mode disabled - re-enabled $count apps"
|
|
}
|