Skip to content

Instantly share code, notes, and snippets.

@MrCarb0n
Last active March 2, 2025 16:34
Show Gist options
  • Save MrCarb0n/a2f5f0f3195b52a084a80e016348ad31 to your computer and use it in GitHub Desktop.
Save MrCarb0n/a2f5f0f3195b52a084a80e016348ad31 to your computer and use it in GitHub Desktop.
Android app runtime permission fixer.
#!/bin/sh
# ─────────────────────────────────────────────
# Android App Permissions Batch Fixer
# Repository: gist.github.com/MrCarb0n
# Author: @MrCarb0n
# ─────────────────────────────────────────────
set -eu
# Colors
GRN="\033[1;32m"
BLU="\033[1;34m"
GRY="\033[0;37m"
RST="\033[0m"
CLR="\033[H\033[J"
# Stats Variables
total_packages=0
granted_permissions=0
failed_permissions=0
granted_appops=0
failed_appops=0
# Draw header dynamically
header() {
local title="Android App Permissions Batch Fixer"
local progress="Processing: $1/$2"
local width=$((${#title} > ${#progress} ? ${#title} + 4 : ${#progress} + 4)) # Dynamic width
printf "${BLU}┌%-${width}s┐\n" ""
printf "│ %-$(($width - 2))s │\n" "$title"
printf "│ %-$(($width - 2))s │\n" "$progress"
printf "└%-${width}s┘${RST}\n" ""
}
# Draw footer dynamically
footer() {
local title="Process Complete"
local width=$((${#title} + 4)) # Dynamic width
printf "${BLU}┌%-${width}s┐\n" ""
printf "│ %-$(($width - 2))s │\n" "$title"
printf "└%-${width}s┘${RST}\n" ""
}
# Display stats
display_stats() {
local title="Summary Statistics"
local perm_line="Permissions: $failed_permissions / $granted_permissions"
local appops_line="AppOps: $failed_appops / $granted_appops"
# Calculate the width dynamically based on the longest line
local width=${#title}
for stat in \
"Total Packages Processed: $total_packages" \
"$perm_line" \
"$appops_line"; do
[ ${#stat} -gt $width ] && width=${#stat}
done
width=$((width + 4)) # Add minimal padding for borders and spaces
# Draw the stats box
printf "\n${BLU}┌%-${width}s┐${RST}\n" ""
printf "${BLU}│ %-$(($width - 2))s │${RST}\n" "$title"
printf "${BLU}├%-${width}s┤${RST}\n" ""
printf "${BLU}│ %-$(($width - 2))s │${RST}\n" "Total Packages Processed: $total_packages"
printf "${BLU}│ %-$(($width - 2))s │${RST}\n" "$perm_line"
printf "${BLU}│ %-$(($width - 2))s │${RST}\n" "$appops_line"
printf "${BLU}└%-${width}s┘${RST}\n" ""
}
PKG_LIST() { dumpsys package packages | grep "Package \[" | awk -F'[][]' '{print $2}' | grep -v "com.termux"; }
PERM_LIST() { dumpsys package permissions | grep "Permission \[" | awk -F'[][]' '{print $2}'; }
DUMP_PERM() {
dumpsys package "$1" | awk '/android.permission/ { match($0, /android.permission\.[A-Z_]+/); if (RSTART) print substr($0, RSTART, RLENGTH); }' | sort -u
}
APPOPS_PERM() {
dumpsys appops --package "$1" | tr -s ' ' '\n' | grep -oE '[A-Z_]{2,}' | sort -u
}
EXEC_PERM() {
set -- $1
count=0
total=$#
for pkg; do
count=$((count + 1))
total_packages=$((total_packages + 1))
# CLR screen and redraw header
printf "${CLR}"
header "$count" "$total"
printf "${BLU} - PKG: %s${RST}\n" "$pkg"
# Process permissions for the current package
for perm in $(DUMP_PERM "$pkg"); do
if pm grant "$pkg" "$perm" 2>/dev/null; then
granted_permissions=$((granted_permissions + 1))
printf "${GRN} GRANTED: %s ${RST}\n" "$perm"
else
failed_permissions=$((failed_permissions + 1))
printf "${GRY} FAILED: %s ${RST}\n" "$perm"
fi
done
done
footer
}
EXEC_APPOPS() {
set -- $1
count=0
total=$#
for pkg; do
count=$((count + 1))
total_packages=$((total_packages + 1))
# CLR screen and redraw header
printf "${CLR}"
header "$count" "$total"
printf "${BLU} - PKG: %s${RST}\n" "$pkg"
# Process appops for the current package
for perm in $(APPOPS_PERM "$pkg"); do
if cmd appops set "$pkg" "$perm" allow 2>/dev/null; then
granted_appops=$((granted_appops + 1))
printf "${GRN} GRANTED: %s ${RST}\n" "$perm"
else
failed_appops=$((failed_appops + 1))
printf "${GRY} FAILED: %s ${RST}\n" "$perm"
fi
done
done
footer
}
# Handle termination gracefully
trap 'display_stats; exit 1' INT TERM
usage() {
printf "${BLU}Usage: %s -[a|p|A|P] [com.pkg.name]${RST}\n" "$0"
printf " -a | -A Apply AppOps permissions\n"
printf " -p | -P Apply package permissions\n"
printf " Example: %s -p com.google.android.youtube\n" "$0"
exit 1
}
[ $# -lt 1 ] && usage
case "$1" in
-a|-A) EXEC_APPOPS "${2:-$(PKG_LIST)}"; display_stats ;;
-p|-P) EXEC_PERM "${2:-$(PKG_LIST)}"; display_stats ;;
*) usage ;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment