mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 19:27:03 +01:00
monitor: split 449 -> 215 + 138 + 136, partitioned by probe kind
lib/monitor.sh was 199 lines over the cap. Its eleven _check_* probes move into two siblings: monitor_checks_health.sh (format indicators, battery, storage, the three enforcer daemons) and monitor_checks_policy.sh (hosts blocklist, DNS chain, launcher, companion app, boot persistence). A single monitor_checks.sh was tried first and left at 265 lines — still over, the net-zero outcome. Two libraries split the cluster at its own seam and land both comfortably under. The _MONITOR_* constants are partitioned by reader so no file assigns a global it never reads. The five read only by the policy probes move into that file; the ones monitor.sh reads itself or shares between both children stay put. shellcheck is clean on each file standing alone. Not a deployment concern: lib/monitor.sh is PC-side, consumed by run_phone.sh, and deploy.sh never references lib/ — so neither copy list changes. Verified three ways: test_monitor.sh reports 9 passed / 0 failed, the same count as before; verify_shell_split.sh confirms all 25 top-level functions moved verbatim; and run_phone.sh --help exits 0, proving the source chain resolves in the real consumer. Over-cap count 24 -> 23. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011w2Pj4Ek3ZNMQVYcFHgXDY
This commit is contained in:
parent
c4bb3e93f6
commit
728301c9a4
17
docs/superpowers/contracts/monitor-split-2026-08-17.json
Normal file
17
docs/superpowers/contracts/monitor-split-2026-08-17.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"title": "split lib/monitor.sh under the 250-line cap",
|
||||
"objective": "Move monitor.sh's eleven _check_* probes into two sibling libraries so every resulting file is under 250 lines, with monitoring behaviour byte-identical.",
|
||||
"acceptance_criteria": [
|
||||
"test_monitor.sh reports exactly 9 passed, 0 failed — the same count as before the split",
|
||||
"verify_shell_split.sh reports all 25 top-level functions moved verbatim",
|
||||
"run_phone.sh --help exits 0, proving the source chain resolves in the real consumer",
|
||||
"shellcheck is clean on each of the three files checked standing alone, with no suppressions",
|
||||
"check_file_length.sh --all drops from 24 over-cap files to 23, with no new file over the cap"
|
||||
],
|
||||
"out_of_scope": [
|
||||
"deploy.sh copy lists: lib/monitor.sh is PC-side and deploy.sh never references lib/",
|
||||
"Any behavioural change to the probes themselves",
|
||||
"Running the probes against a real device"
|
||||
],
|
||||
"verifier": "bash phone_focus_mode/lib/tests/test_monitor.sh + meta/scripts/verify_shell_split.sh + shellcheck"
|
||||
}
|
||||
51
docs/superpowers/evidence/monitor-split-2026-08-17.json
Normal file
51
docs/superpowers/evidence/monitor-split-2026-08-17.json
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
"intent": "Bring phone_focus_mode/lib/monitor.sh under the 250-line cap by moving its health probes into two sibling libraries, without changing any monitoring behaviour.",
|
||||
"scope": [
|
||||
"phone_focus_mode/lib/monitor.sh — 449 lines, now 215",
|
||||
"phone_focus_mode/lib/monitor_checks_health.sh — new, 138 lines",
|
||||
"phone_focus_mode/lib/monitor_checks_policy.sh — new, 136 lines",
|
||||
"Non-goal: deploy.sh copy lists. lib/monitor.sh is a PC-side library consumed by run_phone.sh; deploy.sh never references lib/ and does not push it to the phone."
|
||||
],
|
||||
"changes": [
|
||||
"Moved the six device-health probes (_check_format_indicators, _check_battery, _check_storage, _check_daemon, _check_hosts_daemon, _check_launcher_daemon) into monitor_checks_health.sh.",
|
||||
"Moved the five enforcement-integrity probes (_check_hosts_integrity, _check_dns, _check_launcher, _check_companion_app, _check_boot_persistence) into monitor_checks_policy.sh.",
|
||||
"Partitioned the _MONITOR_* constants by reader so no file assigns a global it never reads (SC2034). The five read only by the policy probes moved into that file; _MONITOR_REMOTE_DIR, _MONITOR_HOSTS_TARGET, _MONITOR_HOSTS_CANDIDATES and the two launcher constants stay in monitor.sh, which reads them or shares them across both children.",
|
||||
"Placed the two source lines after the constant block they depend on, using the already-computed _MONITOR_LIB_DIR rather than recomputing the directory per source line.",
|
||||
"A single-library split was tried first and rejected: it left monitor_checks.sh at 265 lines, still over the cap, which is the net-zero outcome the brief warns about."
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "bash phone_focus_mode/lib/tests/test_monitor.sh",
|
||||
"result": "pass",
|
||||
"evidence": "9 passed, 0 failed — identical to the pre-split baseline captured before any edit. This is the discriminating check: the count matches exactly."
|
||||
},
|
||||
{
|
||||
"command": "bash meta/scripts/verify_shell_split.sh HEAD phone_focus_mode/lib/monitor.sh phone_focus_mode/lib/monitor.sh phone_focus_mode/lib/monitor_checks_health.sh phone_focus_mode/lib/monitor_checks_policy.sh",
|
||||
"result": "pass",
|
||||
"evidence": "'IDENTICAL: all 25 top-level functions moved verbatim'. Note the old path must also be listed among the new paths for a partial split, since 14 functions stayed in monitor.sh; omitting it makes the tool report a false DIFFERENCE with an empty after-set."
|
||||
},
|
||||
{
|
||||
"command": "bash phone_focus_mode/run_phone.sh --help",
|
||||
"result": "pass",
|
||||
"evidence": "Exit 0 with the full usage block, proving the source chain through both new libraries resolves in the real consumer, not just under the test harness."
|
||||
},
|
||||
{
|
||||
"command": "shellcheck phone_focus_mode/lib/monitor.sh phone_focus_mode/lib/monitor_checks_health.sh phone_focus_mode/lib/monitor_checks_policy.sh",
|
||||
"result": "pass",
|
||||
"evidence": "All three clean, each checked standing alone (no -x), so the constant partition holds without a source directive."
|
||||
},
|
||||
{
|
||||
"command": "bash meta/scripts/check_file_length.sh --all",
|
||||
"result": "fail-as-expected",
|
||||
"evidence": "24 files over the cap before, 23 after; monitor.sh at 215 and both new libraries at 138 and 136 are all under. No new file was pushed over."
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"monitor.sh now sources two siblings before defining the helpers they call (_mon_check, _trim_output). This is safe because nothing executes until monitor_collect_snapshot runs, but a future top-level call in either library would break at source time.",
|
||||
"The test covers 9 assertions against helper functions, none of which are the moved _check_* probes; those are device-dependent and unexercised here. The verbatim hash check is what covers them."
|
||||
],
|
||||
"rollback": [
|
||||
"git revert the commit; monitor.sh returns to 449 lines and the two libraries disappear. run_phone.sh needs no change because it only ever sourced monitor.sh.",
|
||||
"After rollback, re-run bash phone_focus_mode/lib/tests/test_monitor.sh and confirm 9 passed, then bash phone_focus_mode/run_phone.sh --help and confirm exit 0."
|
||||
]
|
||||
}
|
||||
@ -8,17 +8,23 @@ set -euo pipefail
|
||||
_MONITOR_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
readonly _MONITOR_LIB_DIR
|
||||
|
||||
# Constants read here or by both probe libraries. Those read by exactly one of
|
||||
# them live in that file instead: a file must not assign a global it never
|
||||
# reads (SC2034), and shellcheck runs without -x so each file stands alone.
|
||||
readonly _MONITOR_REMOTE_DIR="/data/local/tmp/focus_mode"
|
||||
readonly _MONITOR_HOSTS_CANONICAL="/data/local/tmp/focus_mode/hosts.canonical"
|
||||
readonly _MONITOR_HOSTS_SHA_FILE="/data/local/tmp/focus_mode/hosts.sha256"
|
||||
readonly _MONITOR_HOSTS_TARGET="/system/etc/hosts"
|
||||
readonly _MONITOR_BOOT_SCRIPT="/data/adb/service.d/99-focus-mode.sh"
|
||||
readonly _MONITOR_LAUNCHER_PACKAGE="com.qqlabs.minimalistlauncher"
|
||||
readonly _MONITOR_LAUNCHER_ACTIVITY_FILE="/data/local/tmp/focus_mode/minimalist_launcher.activity"
|
||||
readonly _MONITOR_COMPANION_PACKAGE="com.kuhy.focusstatus"
|
||||
readonly _MONITOR_DNS_CHAIN="FOCUS_DNS_BLOCK"
|
||||
readonly _MONITOR_HOSTS_CANDIDATES="/system/etc/hosts /etc/hosts /vendor/etc/hosts /system/system/etc/hosts"
|
||||
|
||||
# Sourced after the constants above, which the probes read. Both libraries call
|
||||
# helpers defined below (_mon_check, _trim_output, _safe_adb_root_output); that
|
||||
# is fine because nothing here runs until monitor_collect_snapshot is called.
|
||||
# shellcheck source=monitor_checks_health.sh
|
||||
. "${_MONITOR_LIB_DIR}/monitor_checks_health.sh"
|
||||
# shellcheck source=monitor_checks_policy.sh
|
||||
. "${_MONITOR_LIB_DIR}/monitor_checks_policy.sh"
|
||||
|
||||
_mon_escape_json() {
|
||||
local escaped="$1"
|
||||
|
||||
@ -145,256 +151,16 @@ monitor_print_format_warning() {
|
||||
_box "PHONE APPEARS TO HAVE BEEN WIPED" "${box_lines[@]}"
|
||||
}
|
||||
|
||||
_check_format_indicators() {
|
||||
local outfile="$1"
|
||||
local -a missing_indicators=()
|
||||
local status="ok"
|
||||
local message="All format indicators are present"
|
||||
|
||||
mapfile -t missing_indicators < <(monitor_check_format_indicators)
|
||||
if (( ${#missing_indicators[@]} >= FORMAT_DETECTION_MIN_MISSING )); then
|
||||
status="fatal"
|
||||
message="Missing ${#missing_indicators[@]} format indicators: ${missing_indicators[*]}"
|
||||
elif (( ${#missing_indicators[@]} > 0 )); then
|
||||
status="warn"
|
||||
message="Missing ${#missing_indicators[@]} format indicators: ${missing_indicators[*]}"
|
||||
fi
|
||||
|
||||
_mon_check "format_indicators" "${status}" "FORMAT_INDICATORS" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_battery() {
|
||||
local outfile="$1"
|
||||
local level=""
|
||||
local health=""
|
||||
local temp=""
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
level="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/level:/{print \$2; exit}'")")"
|
||||
health="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/health:/{print \$2; exit}'")")"
|
||||
temp="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/temperature:/{print \$2; exit}'")")"
|
||||
|
||||
if [[ ! "${level}" =~ ^[0-9]+$ ]]; then
|
||||
status="warn"
|
||||
message="Battery level unavailable"
|
||||
elif (( level < BATTERY_WARN_BELOW )); then
|
||||
status="warn"
|
||||
message="Battery low: ${level}% (threshold ${BATTERY_WARN_BELOW}%)"
|
||||
else
|
||||
message="Battery level ${level}%, health ${health:-unknown}, temp ${temp:-unknown}"
|
||||
fi
|
||||
|
||||
_mon_check "battery" "${status}" "dumpsys battery" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_storage() {
|
||||
local outfile="$1"
|
||||
local free_kb=""
|
||||
local free_mb=0
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
free_kb="$(_trim_output "$(_safe_adb_root_output "df /sdcard 2>/dev/null | awk 'NR==2{print \$4; exit}'")")"
|
||||
if [[ ! "${free_kb}" =~ ^[0-9]+$ ]]; then
|
||||
free_kb="$(_trim_output "$(_safe_adb_root_output "df /storage/emulated/0 2>/dev/null | awk 'NR==2{print \$4; exit}'")")"
|
||||
fi
|
||||
|
||||
if [[ "${free_kb}" =~ ^[0-9]+$ ]]; then
|
||||
free_mb=$((free_kb / 1024))
|
||||
if (( free_mb < STORAGE_WARN_BELOW_MB )); then
|
||||
status="warn"
|
||||
message="Low storage: ${free_mb} MB free (threshold ${STORAGE_WARN_BELOW_MB} MB)"
|
||||
else
|
||||
message="Free storage: ${free_mb} MB"
|
||||
fi
|
||||
else
|
||||
status="warn"
|
||||
message="Free storage unavailable"
|
||||
fi
|
||||
|
||||
_mon_check "storage" "${status}" "df /sdcard" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_daemon() {
|
||||
local daemon_name="$1"
|
||||
local script_name="$2"
|
||||
local pidfile="$3"
|
||||
local outfile="$4"
|
||||
local pid=""
|
||||
local pgrep_pid=""
|
||||
|
||||
pid="$(_monitor_read_pidfile "${pidfile}")"
|
||||
if [[ "${pid}" =~ ^[0-9]+$ ]] && _monitor_pid_matches_script "${pid}" "${script_name}"; then
|
||||
_mon_check "${daemon_name}" "ok" "${pidfile}" "${daemon_name} running (PID ${pid})" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
pgrep_pid="$(_trim_output "$(_safe_adb_root_output "pgrep -f '${script_name}' 2>/dev/null | head -1")")"
|
||||
if [[ "${pgrep_pid}" =~ ^[0-9]+$ ]] && adb_root_shell "kill -0 ${pgrep_pid} >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
_mon_check "${daemon_name}" "ok" "pgrep -f ${script_name}" "${daemon_name} running (PID ${pgrep_pid})" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_mon_check "${daemon_name}" "error" "${pidfile}" "${daemon_name} is NOT running" "true" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_hosts_daemon() {
|
||||
local outfile="$1"
|
||||
local resolved_target=""
|
||||
|
||||
resolved_target="$(_monitor_resolve_hosts_target)"
|
||||
if [[ -z "${resolved_target}" ]]; then
|
||||
_mon_check "hosts_enforcer" "warn" "hosts target probe" \
|
||||
"No hosts target file exists on this ROM; hosts daemon check skipped" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_check_daemon "hosts_enforcer" "hosts_enforcer.sh" "${_MONITOR_REMOTE_DIR}/hosts_enforcer.pid" "${outfile}"
|
||||
}
|
||||
|
||||
_check_launcher_daemon() {
|
||||
local outfile="$1"
|
||||
local has_snapshot="no"
|
||||
local launcher_installed="no"
|
||||
|
||||
if adb_root_shell "test -s '${_MONITOR_LAUNCHER_ACTIVITY_FILE}'" >/dev/null 2>&1; then
|
||||
has_snapshot="yes"
|
||||
fi
|
||||
|
||||
if adb_root_shell "pm path '${_MONITOR_LAUNCHER_PACKAGE}' >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
launcher_installed="yes"
|
||||
fi
|
||||
|
||||
if [[ "${has_snapshot}" == "no" && "${launcher_installed}" == "no" ]]; then
|
||||
_mon_check "launcher_enforcer" "warn" "launcher optional probe" \
|
||||
"Launcher enforcer check skipped (launcher not configured yet)" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_check_daemon "launcher_enforcer" "launcher_enforcer.sh" "${_MONITOR_REMOTE_DIR}/launcher_enforcer.pid" "${outfile}"
|
||||
}
|
||||
|
||||
_check_hosts_integrity() {
|
||||
local outfile="$1"
|
||||
local hosts_target=""
|
||||
local expected_hash=""
|
||||
local actual_hash=""
|
||||
|
||||
hosts_target="$(_monitor_resolve_hosts_target)"
|
||||
if [[ -z "${hosts_target}" ]]; then
|
||||
_mon_check "hosts_integrity" "warn" "hosts target probe" \
|
||||
"No hosts file target exists on this ROM; hosts integrity check skipped" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! adb_root_shell "test -f ${_MONITOR_HOSTS_CANONICAL}" >/dev/null 2>&1; then
|
||||
_mon_check "hosts_integrity" "fatal" "${_MONITOR_HOSTS_CANONICAL}" \
|
||||
"Canonical hosts file missing at ${_MONITOR_HOSTS_CANONICAL}" "true" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
expected_hash="$(_trim_output "$(_safe_adb_root_output "cat ${_MONITOR_HOSTS_SHA_FILE} 2>/dev/null")")"
|
||||
actual_hash="$(_trim_output "$(_safe_adb_root_output "sha256sum ${hosts_target} 2>/dev/null | awk '{print \$1}'")")"
|
||||
|
||||
if [[ -z "${expected_hash}" || -z "${actual_hash}" ]]; then
|
||||
_mon_check "hosts_integrity" "error" "${hosts_target}" \
|
||||
"Could not read hosts integrity hashes" "true" >>"${outfile}"
|
||||
elif [[ "${expected_hash}" == "${actual_hash}" ]]; then
|
||||
_mon_check "hosts_integrity" "ok" "${hosts_target}" \
|
||||
"Hosts file matches canonical (${actual_hash:0:12}…)" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "hosts_integrity" "error" "${hosts_target}" \
|
||||
"Hosts mismatch: active ${actual_hash:0:12}… != expected ${expected_hash:0:12}…" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_dns() {
|
||||
local outfile="$1"
|
||||
local private_dns_mode=""
|
||||
local chain_present="no"
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
private_dns_mode="$(_trim_output "$(_safe_adb_root_output "settings get global private_dns_mode 2>/dev/null")")"
|
||||
if adb_root_shell "iptables -L ${_MONITOR_DNS_CHAIN} >/dev/null 2>&1 && ip6tables -L ${_MONITOR_DNS_CHAIN} >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
chain_present="yes"
|
||||
fi
|
||||
|
||||
if [[ "${private_dns_mode}" == "off" || "${private_dns_mode}" == "null" || -z "${private_dns_mode}" ]]; then
|
||||
if [[ "${chain_present}" == "yes" ]]; then
|
||||
message="Private DNS disabled and DNS firewall chains present"
|
||||
else
|
||||
status="error"
|
||||
message="Private DNS disabled, but DNS firewall chains are missing"
|
||||
fi
|
||||
else
|
||||
status="error"
|
||||
message="Private DNS is enabled (mode=${private_dns_mode})"
|
||||
fi
|
||||
|
||||
_mon_check "dns_enforcement" "${status}" "settings get global private_dns_mode" "${message}" "true" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_launcher() {
|
||||
local outfile="$1"
|
||||
local desired_activity=""
|
||||
local actual_activity=""
|
||||
local has_snapshot="no"
|
||||
|
||||
if adb_root_shell "test -s '${_MONITOR_LAUNCHER_ACTIVITY_FILE}'" >/dev/null 2>&1; then
|
||||
has_snapshot="yes"
|
||||
fi
|
||||
|
||||
if ! adb_root_shell "pm path '${_MONITOR_LAUNCHER_PACKAGE}' >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
if [[ "${has_snapshot}" == "yes" ]]; then
|
||||
_mon_check "launcher_state" "fatal" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher is not installed but snapshot metadata exists" "true" >>"${outfile}"
|
||||
else
|
||||
_mon_check "launcher_state" "warn" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher is not installed (optional until snapshot is configured)" "false" >>"${outfile}"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
desired_activity="$(_trim_output "$(_safe_adb_root_output "cat ${_MONITOR_LAUNCHER_ACTIVITY_FILE} 2>/dev/null")")"
|
||||
actual_activity="$(_trim_output "$(_safe_adb_root_output "cmd package resolve-activity --brief -c android.intent.category.HOME -a android.intent.action.MAIN 2>/dev/null | awk 'NR==2{print}'")")"
|
||||
|
||||
if [[ -z "${desired_activity}" ]]; then
|
||||
_mon_check "launcher_state" "warn" "cat ${_MONITOR_LAUNCHER_ACTIVITY_FILE}" \
|
||||
"Launcher snapshot metadata is missing or empty" "true" >>"${outfile}"
|
||||
elif [[ -n "${actual_activity}" && "${desired_activity}" != "${actual_activity}" ]]; then
|
||||
_mon_check "launcher_state" "error" "cmd package resolve-activity" \
|
||||
"Launcher default mismatch: expected ${desired_activity}, got ${actual_activity}" "true" >>"${outfile}"
|
||||
else
|
||||
_mon_check "launcher_state" "ok" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher installed and HOME activity aligned" "false" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_companion_app() {
|
||||
local outfile="$1"
|
||||
|
||||
if adb_root_shell "pm list packages -e '${_MONITOR_COMPANION_PACKAGE}' 2>/dev/null | grep -q '${_MONITOR_COMPANION_PACKAGE}'" >/dev/null 2>&1; then
|
||||
_mon_check "companion_app" "ok" "pm list packages -e ${_MONITOR_COMPANION_PACKAGE}" \
|
||||
"Focus companion app is installed" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "companion_app" "warn" "pm list packages -e ${_MONITOR_COMPANION_PACKAGE}" \
|
||||
"Focus companion app is missing" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_boot_persistence() {
|
||||
local outfile="$1"
|
||||
|
||||
if adb_root_shell "test -x ${_MONITOR_BOOT_SCRIPT}" >/dev/null 2>&1; then
|
||||
_mon_check "boot_persistence" "ok" "test -x ${_MONITOR_BOOT_SCRIPT}" \
|
||||
"Magisk boot script present and executable" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "boot_persistence" "fatal" "test -x ${_MONITOR_BOOT_SCRIPT}" \
|
||||
"Magisk boot script missing or not executable" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_collect_snapshot() {
|
||||
local snapshot_dir="$1"
|
||||
|
||||
138
phone_focus_mode/lib/monitor_checks_health.sh
Executable file
138
phone_focus_mode/lib/monitor_checks_health.sh
Executable file
@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/monitor_checks_health.sh — device-health probes behind monitor.sh:
|
||||
# format indicators, battery, storage, and the three enforcer daemons.
|
||||
# Each _check_* appends one JSON object to the checks file it is given.
|
||||
#
|
||||
# Sourced by monitor.sh, which defines every _MONITOR_* constant these read
|
||||
# and the _mon_check/_trim_output/_monitor_read_pidfile helpers they call.
|
||||
# Nothing is assigned here, so there is no constant to keep in step.
|
||||
|
||||
_check_format_indicators() {
|
||||
local outfile="$1"
|
||||
local -a missing_indicators=()
|
||||
local status="ok"
|
||||
local message="All format indicators are present"
|
||||
|
||||
mapfile -t missing_indicators < <(monitor_check_format_indicators)
|
||||
if (( ${#missing_indicators[@]} >= FORMAT_DETECTION_MIN_MISSING )); then
|
||||
status="fatal"
|
||||
message="Missing ${#missing_indicators[@]} format indicators: ${missing_indicators[*]}"
|
||||
elif (( ${#missing_indicators[@]} > 0 )); then
|
||||
status="warn"
|
||||
message="Missing ${#missing_indicators[@]} format indicators: ${missing_indicators[*]}"
|
||||
fi
|
||||
|
||||
_mon_check "format_indicators" "${status}" "FORMAT_INDICATORS" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_battery() {
|
||||
local outfile="$1"
|
||||
local level=""
|
||||
local health=""
|
||||
local temp=""
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
level="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/level:/{print \$2; exit}'")")"
|
||||
health="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/health:/{print \$2; exit}'")")"
|
||||
temp="$(_trim_output "$(_safe_adb_root_output "dumpsys battery | awk -F': ' '/temperature:/{print \$2; exit}'")")"
|
||||
|
||||
if [[ ! "${level}" =~ ^[0-9]+$ ]]; then
|
||||
status="warn"
|
||||
message="Battery level unavailable"
|
||||
elif (( level < BATTERY_WARN_BELOW )); then
|
||||
status="warn"
|
||||
message="Battery low: ${level}% (threshold ${BATTERY_WARN_BELOW}%)"
|
||||
else
|
||||
message="Battery level ${level}%, health ${health:-unknown}, temp ${temp:-unknown}"
|
||||
fi
|
||||
|
||||
_mon_check "battery" "${status}" "dumpsys battery" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_storage() {
|
||||
local outfile="$1"
|
||||
local free_kb=""
|
||||
local free_mb=0
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
free_kb="$(_trim_output "$(_safe_adb_root_output "df /sdcard 2>/dev/null | awk 'NR==2{print \$4; exit}'")")"
|
||||
if [[ ! "${free_kb}" =~ ^[0-9]+$ ]]; then
|
||||
free_kb="$(_trim_output "$(_safe_adb_root_output "df /storage/emulated/0 2>/dev/null | awk 'NR==2{print \$4; exit}'")")"
|
||||
fi
|
||||
|
||||
if [[ "${free_kb}" =~ ^[0-9]+$ ]]; then
|
||||
free_mb=$((free_kb / 1024))
|
||||
if (( free_mb < STORAGE_WARN_BELOW_MB )); then
|
||||
status="warn"
|
||||
message="Low storage: ${free_mb} MB free (threshold ${STORAGE_WARN_BELOW_MB} MB)"
|
||||
else
|
||||
message="Free storage: ${free_mb} MB"
|
||||
fi
|
||||
else
|
||||
status="warn"
|
||||
message="Free storage unavailable"
|
||||
fi
|
||||
|
||||
_mon_check "storage" "${status}" "df /sdcard" "${message}" "false" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_daemon() {
|
||||
local daemon_name="$1"
|
||||
local script_name="$2"
|
||||
local pidfile="$3"
|
||||
local outfile="$4"
|
||||
local pid=""
|
||||
local pgrep_pid=""
|
||||
|
||||
pid="$(_monitor_read_pidfile "${pidfile}")"
|
||||
if [[ "${pid}" =~ ^[0-9]+$ ]] && _monitor_pid_matches_script "${pid}" "${script_name}"; then
|
||||
_mon_check "${daemon_name}" "ok" "${pidfile}" "${daemon_name} running (PID ${pid})" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
pgrep_pid="$(_trim_output "$(_safe_adb_root_output "pgrep -f '${script_name}' 2>/dev/null | head -1")")"
|
||||
if [[ "${pgrep_pid}" =~ ^[0-9]+$ ]] && adb_root_shell "kill -0 ${pgrep_pid} >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
_mon_check "${daemon_name}" "ok" "pgrep -f ${script_name}" "${daemon_name} running (PID ${pgrep_pid})" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_mon_check "${daemon_name}" "error" "${pidfile}" "${daemon_name} is NOT running" "true" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_hosts_daemon() {
|
||||
local outfile="$1"
|
||||
local resolved_target=""
|
||||
|
||||
resolved_target="$(_monitor_resolve_hosts_target)"
|
||||
if [[ -z "${resolved_target}" ]]; then
|
||||
_mon_check "hosts_enforcer" "warn" "hosts target probe" \
|
||||
"No hosts target file exists on this ROM; hosts daemon check skipped" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_check_daemon "hosts_enforcer" "hosts_enforcer.sh" "${_MONITOR_REMOTE_DIR}/hosts_enforcer.pid" "${outfile}"
|
||||
}
|
||||
|
||||
_check_launcher_daemon() {
|
||||
local outfile="$1"
|
||||
local has_snapshot="no"
|
||||
local launcher_installed="no"
|
||||
|
||||
if adb_root_shell "test -s '${_MONITOR_LAUNCHER_ACTIVITY_FILE}'" >/dev/null 2>&1; then
|
||||
has_snapshot="yes"
|
||||
fi
|
||||
|
||||
if adb_root_shell "pm path '${_MONITOR_LAUNCHER_PACKAGE}' >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
launcher_installed="yes"
|
||||
fi
|
||||
|
||||
if [[ "${has_snapshot}" == "no" && "${launcher_installed}" == "no" ]]; then
|
||||
_mon_check "launcher_enforcer" "warn" "launcher optional probe" \
|
||||
"Launcher enforcer check skipped (launcher not configured yet)" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
_check_daemon "launcher_enforcer" "launcher_enforcer.sh" "${_MONITOR_REMOTE_DIR}/launcher_enforcer.pid" "${outfile}"
|
||||
}
|
||||
136
phone_focus_mode/lib/monitor_checks_policy.sh
Executable file
136
phone_focus_mode/lib/monitor_checks_policy.sh
Executable file
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env bash
|
||||
# lib/monitor_checks_policy.sh — enforcement-integrity probes behind monitor.sh:
|
||||
# the hosts blocklist, DNS chain, launcher, companion app and boot persistence.
|
||||
# Each _check_* appends one JSON object to the checks file it is given.
|
||||
#
|
||||
# Sourced by monitor.sh, which defines _MONITOR_LAUNCHER_PACKAGE and
|
||||
# _MONITOR_LAUNCHER_ACTIVITY_FILE (shared with the health probes) plus the
|
||||
# _mon_check/_trim_output/_safe_adb_root_output helpers these call.
|
||||
# The constants below are read only here, so they are assigned only here.
|
||||
|
||||
readonly _MONITOR_HOSTS_CANONICAL="/data/local/tmp/focus_mode/hosts.canonical"
|
||||
readonly _MONITOR_HOSTS_SHA_FILE="/data/local/tmp/focus_mode/hosts.sha256"
|
||||
readonly _MONITOR_BOOT_SCRIPT="/data/adb/service.d/99-focus-mode.sh"
|
||||
readonly _MONITOR_COMPANION_PACKAGE="com.kuhy.focusstatus"
|
||||
readonly _MONITOR_DNS_CHAIN="FOCUS_DNS_BLOCK"
|
||||
|
||||
_check_hosts_integrity() {
|
||||
local outfile="$1"
|
||||
local hosts_target=""
|
||||
local expected_hash=""
|
||||
local actual_hash=""
|
||||
|
||||
hosts_target="$(_monitor_resolve_hosts_target)"
|
||||
if [[ -z "${hosts_target}" ]]; then
|
||||
_mon_check "hosts_integrity" "warn" "hosts target probe" \
|
||||
"No hosts file target exists on this ROM; hosts integrity check skipped" "false" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! adb_root_shell "test -f ${_MONITOR_HOSTS_CANONICAL}" >/dev/null 2>&1; then
|
||||
_mon_check "hosts_integrity" "fatal" "${_MONITOR_HOSTS_CANONICAL}" \
|
||||
"Canonical hosts file missing at ${_MONITOR_HOSTS_CANONICAL}" "true" >>"${outfile}"
|
||||
return
|
||||
fi
|
||||
|
||||
expected_hash="$(_trim_output "$(_safe_adb_root_output "cat ${_MONITOR_HOSTS_SHA_FILE} 2>/dev/null")")"
|
||||
actual_hash="$(_trim_output "$(_safe_adb_root_output "sha256sum ${hosts_target} 2>/dev/null | awk '{print \$1}'")")"
|
||||
|
||||
if [[ -z "${expected_hash}" || -z "${actual_hash}" ]]; then
|
||||
_mon_check "hosts_integrity" "error" "${hosts_target}" \
|
||||
"Could not read hosts integrity hashes" "true" >>"${outfile}"
|
||||
elif [[ "${expected_hash}" == "${actual_hash}" ]]; then
|
||||
_mon_check "hosts_integrity" "ok" "${hosts_target}" \
|
||||
"Hosts file matches canonical (${actual_hash:0:12}…)" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "hosts_integrity" "error" "${hosts_target}" \
|
||||
"Hosts mismatch: active ${actual_hash:0:12}… != expected ${expected_hash:0:12}…" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_dns() {
|
||||
local outfile="$1"
|
||||
local private_dns_mode=""
|
||||
local chain_present="no"
|
||||
local status="ok"
|
||||
local message=""
|
||||
|
||||
private_dns_mode="$(_trim_output "$(_safe_adb_root_output "settings get global private_dns_mode 2>/dev/null")")"
|
||||
if adb_root_shell "iptables -L ${_MONITOR_DNS_CHAIN} >/dev/null 2>&1 && ip6tables -L ${_MONITOR_DNS_CHAIN} >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
chain_present="yes"
|
||||
fi
|
||||
|
||||
if [[ "${private_dns_mode}" == "off" || "${private_dns_mode}" == "null" || -z "${private_dns_mode}" ]]; then
|
||||
if [[ "${chain_present}" == "yes" ]]; then
|
||||
message="Private DNS disabled and DNS firewall chains present"
|
||||
else
|
||||
status="error"
|
||||
message="Private DNS disabled, but DNS firewall chains are missing"
|
||||
fi
|
||||
else
|
||||
status="error"
|
||||
message="Private DNS is enabled (mode=${private_dns_mode})"
|
||||
fi
|
||||
|
||||
_mon_check "dns_enforcement" "${status}" "settings get global private_dns_mode" "${message}" "true" >>"${outfile}"
|
||||
}
|
||||
|
||||
_check_launcher() {
|
||||
local outfile="$1"
|
||||
local desired_activity=""
|
||||
local actual_activity=""
|
||||
local has_snapshot="no"
|
||||
|
||||
if adb_root_shell "test -s '${_MONITOR_LAUNCHER_ACTIVITY_FILE}'" >/dev/null 2>&1; then
|
||||
has_snapshot="yes"
|
||||
fi
|
||||
|
||||
if ! adb_root_shell "pm path '${_MONITOR_LAUNCHER_PACKAGE}' >/dev/null 2>&1" >/dev/null 2>&1; then
|
||||
if [[ "${has_snapshot}" == "yes" ]]; then
|
||||
_mon_check "launcher_state" "fatal" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher is not installed but snapshot metadata exists" "true" >>"${outfile}"
|
||||
else
|
||||
_mon_check "launcher_state" "warn" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher is not installed (optional until snapshot is configured)" "false" >>"${outfile}"
|
||||
fi
|
||||
return
|
||||
fi
|
||||
|
||||
desired_activity="$(_trim_output "$(_safe_adb_root_output "cat ${_MONITOR_LAUNCHER_ACTIVITY_FILE} 2>/dev/null")")"
|
||||
actual_activity="$(_trim_output "$(_safe_adb_root_output "cmd package resolve-activity --brief -c android.intent.category.HOME -a android.intent.action.MAIN 2>/dev/null | awk 'NR==2{print}'")")"
|
||||
|
||||
if [[ -z "${desired_activity}" ]]; then
|
||||
_mon_check "launcher_state" "warn" "cat ${_MONITOR_LAUNCHER_ACTIVITY_FILE}" \
|
||||
"Launcher snapshot metadata is missing or empty" "true" >>"${outfile}"
|
||||
elif [[ -n "${actual_activity}" && "${desired_activity}" != "${actual_activity}" ]]; then
|
||||
_mon_check "launcher_state" "error" "cmd package resolve-activity" \
|
||||
"Launcher default mismatch: expected ${desired_activity}, got ${actual_activity}" "true" >>"${outfile}"
|
||||
else
|
||||
_mon_check "launcher_state" "ok" "pm path ${_MONITOR_LAUNCHER_PACKAGE}" \
|
||||
"Minimalist launcher installed and HOME activity aligned" "false" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_companion_app() {
|
||||
local outfile="$1"
|
||||
|
||||
if adb_root_shell "pm list packages -e '${_MONITOR_COMPANION_PACKAGE}' 2>/dev/null | grep -q '${_MONITOR_COMPANION_PACKAGE}'" >/dev/null 2>&1; then
|
||||
_mon_check "companion_app" "ok" "pm list packages -e ${_MONITOR_COMPANION_PACKAGE}" \
|
||||
"Focus companion app is installed" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "companion_app" "warn" "pm list packages -e ${_MONITOR_COMPANION_PACKAGE}" \
|
||||
"Focus companion app is missing" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
|
||||
_check_boot_persistence() {
|
||||
local outfile="$1"
|
||||
|
||||
if adb_root_shell "test -x ${_MONITOR_BOOT_SCRIPT}" >/dev/null 2>&1; then
|
||||
_mon_check "boot_persistence" "ok" "test -x ${_MONITOR_BOOT_SCRIPT}" \
|
||||
"Magisk boot script present and executable" "false" >>"${outfile}"
|
||||
else
|
||||
_mon_check "boot_persistence" "fatal" "test -x ${_MONITOR_BOOT_SCRIPT}" \
|
||||
"Magisk boot script missing or not executable" "true" >>"${outfile}"
|
||||
fi
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user