009: publish AXPR23 final source and public documentation
This commit is contained in:
1 parent
72930e0fd6
commit
2c714d8d34
35 files changed
+2498
-403
No files matched your search
Executable
+296
@@ -0,0 +1,296 @@
|
||||
#!/system/bin/sh
|
||||
|
||||
set -u
|
||||
|
||||
STATE_DIR=${INTELLIRAT_STATE_DIR:-/data/local/tmp}
|
||||
CONFIG_FILE=${INTELLIRAT_CONFIG:-$STATE_DIR/config.conf}
|
||||
LOG_FILE=${INTELLIRAT_LOG:-$STATE_DIR/events.log}
|
||||
CMD_BIN=${INTELLIRAT_CMD:-cmd}
|
||||
DUMPSYS_BIN=${INTELLIRAT_DUMPSYS:-dumpsys}
|
||||
|
||||
DEFAULT_SLOT=0
|
||||
DEFAULT_HIGH_MASK=00011101001110000111
|
||||
DEFAULT_LOW_MASK=00011100001110000111
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
IntelliRAT v0.1 manual prototype
|
||||
|
||||
Usage:
|
||||
intellirat status [slot]
|
||||
intellirat capture [slot]
|
||||
intellirat high [slot]
|
||||
intellirat low [slot]
|
||||
intellirat restore [slot]
|
||||
intellirat --dry-run high|low|restore [slot]
|
||||
|
||||
The prototype never changes RAT automatically. Capture the current state before
|
||||
the first transition. Restore returns the captured user network mask.
|
||||
EOF
|
||||
}
|
||||
|
||||
fail() {
|
||||
printf 'IntelliRAT: %s\n' "$*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
load_config() {
|
||||
TARGET_SLOT=$DEFAULT_SLOT
|
||||
HIGH_MASK=$DEFAULT_HIGH_MASK
|
||||
LOW_MASK=$DEFAULT_LOW_MASK
|
||||
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
# The file is created root-only by service.sh; reject unsafe ownership
|
||||
# only when the platform exposes stat in the available shell.
|
||||
# shellcheck disable=SC1090
|
||||
. "$CONFIG_FILE"
|
||||
fi
|
||||
|
||||
case "$TARGET_SLOT" in
|
||||
''|*[!0-9]*) fail "invalid TARGET_SLOT" ;;
|
||||
esac
|
||||
case "$HIGH_MASK:$LOW_MASK" in
|
||||
*[!01:]*|:*) fail "masks must be non-empty binary strings" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ensure_state_dir() {
|
||||
mkdir -p "$STATE_DIR" || fail "cannot create $STATE_DIR"
|
||||
if [ "$STATE_DIR" = /data/local/tmp ]; then
|
||||
return
|
||||
fi
|
||||
chown 0 2000 "$STATE_DIR" 2>/dev/null || true
|
||||
chmod 0770 "$STATE_DIR" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_event() {
|
||||
ensure_state_dir
|
||||
printf '%s %s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" "$*" >> "$LOG_FILE"
|
||||
chmod 0600 "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
slot_or_default() {
|
||||
if [ "${1:-}" = '' ]; then
|
||||
printf '%s' "$TARGET_SLOT"
|
||||
else
|
||||
case "$1" in
|
||||
''|*[!0-9]*) fail "invalid slot: $1" ;;
|
||||
esac
|
||||
printf '%s' "$1"
|
||||
fi
|
||||
}
|
||||
|
||||
state_file() {
|
||||
printf '%s/intellirat-sub-%s.state' "$STATE_DIR" "$1"
|
||||
}
|
||||
|
||||
read_user_names() {
|
||||
slot=$1
|
||||
result=$(
|
||||
"$CMD_BIN" phone get-allowed-network-types-for-users -s "$slot" 2>&1
|
||||
) || fail "cannot read network types for slot $slot: $result"
|
||||
case "$result" in
|
||||
*'No valid subscription found'*|*'No valid NETWORK_TYPES_BITMASK'*)
|
||||
fail "no valid subscription for slot $slot: $result"
|
||||
;;
|
||||
esac
|
||||
result=$(printf '%s' "$result" | tr -d '[:space:]\r\n')
|
||||
[ -n "$result" ] || fail "empty network type response for slot $slot"
|
||||
printf '%s' "$result"
|
||||
}
|
||||
|
||||
network_names_to_decimal() {
|
||||
names=$1
|
||||
mask=0
|
||||
old_ifs=$IFS
|
||||
IFS='|'
|
||||
# shellcheck disable=SC2086
|
||||
for name in $names; do
|
||||
case "$name" in
|
||||
GPRS) mask=$((mask | 1)) ;;
|
||||
EDGE) mask=$((mask | 2)) ;;
|
||||
UMTS) mask=$((mask | 4)) ;;
|
||||
CDMA) mask=$((mask | 8)) ;;
|
||||
EVDO_0) mask=$((mask | 16)) ;;
|
||||
EVDO_A) mask=$((mask | 32)) ;;
|
||||
1xRTT) mask=$((mask | 64)) ;;
|
||||
HSDPA) mask=$((mask | 128)) ;;
|
||||
HSUPA) mask=$((mask | 256)) ;;
|
||||
HSPA) mask=$((mask | 512)) ;;
|
||||
HSPA+) mask=$((mask | 16384)) ;;
|
||||
IDEN) mask=$((mask | 1024)) ;;
|
||||
EVDO_B) mask=$((mask | 2048)) ;;
|
||||
LTE) mask=$((mask | 4096)) ;;
|
||||
EHRPD) mask=$((mask | 8192)) ;;
|
||||
HSPAP) mask=$((mask | 16384)) ;;
|
||||
GSM) mask=$((mask | 32768)) ;;
|
||||
TD_SCDMA) mask=$((mask | 65536)) ;;
|
||||
IWLAN) mask=$((mask | 131072)) ;;
|
||||
LTE_CA) mask=$((mask | 4096)) ;;
|
||||
NR) mask=$((mask | 524288)) ;;
|
||||
UNKNOWN|NONE) ;;
|
||||
*) IFS=$old_ifs; fail "unknown network type from telephony: $name" ;;
|
||||
esac
|
||||
done
|
||||
IFS=$old_ifs
|
||||
printf '%s' "$mask"
|
||||
}
|
||||
|
||||
decimal_to_binary() {
|
||||
mask=$1
|
||||
output=
|
||||
bit=19
|
||||
while [ "$bit" -ge 0 ]; do
|
||||
value=$((1 << bit))
|
||||
if [ $((mask & value)) -ne 0 ]; then
|
||||
output="${output}1"
|
||||
else
|
||||
output="${output}0"
|
||||
fi
|
||||
bit=$((bit - 1))
|
||||
done
|
||||
printf '%s' "$output"
|
||||
}
|
||||
|
||||
read_user_binary() {
|
||||
names=$(read_user_names "$1")
|
||||
decimal=$(network_names_to_decimal "$names")
|
||||
decimal_to_binary "$decimal"
|
||||
}
|
||||
|
||||
call_in_progress() {
|
||||
dump=$(
|
||||
"$DUMPSYS_BIN" telecom 2>/dev/null || true
|
||||
)
|
||||
current_calls=$(printf '%s\n' "$dump" | awk '
|
||||
/^ All calls:/ { in_calls=1; next }
|
||||
/^ Active dialing, or connecting calls:/ { in_calls=1; next }
|
||||
/^ Ringing calls:/ { in_calls=1; next }
|
||||
/^ Holding calls:/ { in_calls=1; next }
|
||||
/^[[:space:]]*[A-Za-z][A-Za-z _-]*:$/ { in_calls=0 }
|
||||
in_calls { print }
|
||||
')
|
||||
printf '%s\n' "$current_calls" | grep -Eq \
|
||||
'(^|[^A-Za-z])(ACTIVE|RINGING|DIALING|CONNECTING)([^A-Za-z]|$)|mCallState=(ACTIVE|RINGING|DIALING|CONNECTING)'
|
||||
}
|
||||
|
||||
write_state() {
|
||||
slot=$1
|
||||
original_names=$2
|
||||
original_binary=$3
|
||||
file=$(state_file "$slot")
|
||||
tmp="${file}.tmp.$$"
|
||||
{
|
||||
printf 'original_names=%s\n' "$original_names"
|
||||
printf 'original_mask=%s\n' "$original_binary"
|
||||
printf 'captured_at=%s\n' "$(date -u '+%Y-%m-%dT%H:%M:%SZ')"
|
||||
} > "$tmp" || fail "cannot write $file"
|
||||
chmod 0600 "$tmp"
|
||||
mv "$tmp" "$file" || fail "cannot commit $file"
|
||||
}
|
||||
|
||||
capture() {
|
||||
slot=$1
|
||||
ensure_state_dir
|
||||
names=$(read_user_names "$slot")
|
||||
decimal=$(network_names_to_decimal "$names")
|
||||
binary=$(decimal_to_binary "$decimal")
|
||||
file=$(state_file "$slot")
|
||||
if [ -f "$file" ] && [ "${INTELLIRAT_FORCE_CAPTURE:-0}" != 1 ]; then
|
||||
fail "state already captured for slot $slot; set INTELLIRAT_FORCE_CAPTURE=1 to replace it"
|
||||
fi
|
||||
write_state "$slot" "$names" "$binary"
|
||||
log_event "capture slot=$slot mask=$binary names=$names"
|
||||
printf 'captured slot=%s mask=%s names=%s\n' "$slot" "$binary" "$names"
|
||||
}
|
||||
|
||||
get_original_mask() {
|
||||
file=$(state_file "$1")
|
||||
[ -f "$file" ] || {
|
||||
printf '%s' "$HIGH_MASK"
|
||||
return
|
||||
}
|
||||
value=$(grep '^original_mask=' "$file" | cut -d= -f2-)
|
||||
case "$value" in
|
||||
''|*[!01]*) fail "invalid saved state for slot $1" ;;
|
||||
esac
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
apply_mask() {
|
||||
slot=$1
|
||||
target=$2
|
||||
reason=$3
|
||||
current=$(read_user_binary "$slot")
|
||||
if [ "$current" = "$target" ]; then
|
||||
log_event "noop slot=$slot state=$reason mask=$target"
|
||||
printf 'already state=%s slot=%s mask=%s\n' "$reason" "$slot" "$target"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if call_in_progress; then
|
||||
fail "telephony call is active; transition refused"
|
||||
fi
|
||||
|
||||
if [ "${INTELLIRAT_DRY_RUN:-0}" = 1 ]; then
|
||||
printf 'dry-run cmd phone set-allowed-network-types-for-users -s %s %s\n' \
|
||||
"$slot" "$target"
|
||||
return 0
|
||||
fi
|
||||
|
||||
result=$(
|
||||
"$CMD_BIN" phone set-allowed-network-types-for-users -s "$slot" "$target" 2>&1
|
||||
) || fail "network transition failed: $result"
|
||||
case "$result" in
|
||||
*completed*) ;;
|
||||
*) fail "telephony did not confirm transition: $result" ;;
|
||||
esac
|
||||
|
||||
actual=$(read_user_binary "$slot")
|
||||
[ "$actual" = "$target" ] || fail "verification mismatch: requested=$target actual=$actual"
|
||||
log_event "transition slot=$slot previous=$current state=$reason requested=$target actual=$actual"
|
||||
printf 'transition slot=%s state=%s previous=%s actual=%s\n' \
|
||||
"$slot" "$reason" "$current" "$actual"
|
||||
}
|
||||
|
||||
status() {
|
||||
slot=$1
|
||||
names=$(read_user_names "$slot")
|
||||
decimal=$(network_names_to_decimal "$names")
|
||||
current=$(decimal_to_binary "$decimal")
|
||||
state=UNKNOWN
|
||||
[ "$current" = "$HIGH_MASK" ] && state=HIGH
|
||||
[ "$current" = "$LOW_MASK" ] && state=LOW
|
||||
saved=NO
|
||||
[ -f "$(state_file "$slot")" ] && saved=YES
|
||||
printf 'slot=%s state=%s mask=%s names=%s saved_original=%s\n' \
|
||||
"$slot" "$state" "$current" "$names" "$saved"
|
||||
}
|
||||
|
||||
main() {
|
||||
dry_run=0
|
||||
if [ "${1:-}" = '--dry-run' ]; then
|
||||
dry_run=1
|
||||
INTELLIRAT_DRY_RUN=1
|
||||
export INTELLIRAT_DRY_RUN
|
||||
shift
|
||||
fi
|
||||
load_config
|
||||
ensure_state_dir
|
||||
|
||||
command=${1:-help}
|
||||
shift || true
|
||||
slot=$(slot_or_default "${1:-}")
|
||||
|
||||
case "$command" in
|
||||
help|-h|--help) usage ;;
|
||||
status) status "$slot" ;;
|
||||
capture) capture "$slot" ;;
|
||||
high) apply_mask "$slot" "$HIGH_MASK" HIGH ;;
|
||||
low) apply_mask "$slot" "$LOW_MASK" LOW ;;
|
||||
restore) apply_mask "$slot" "$(get_original_mask "$slot")" RESTORE ;;
|
||||
*) usage >&2; exit 2 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in new issue
Block a user