Files

41 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Replace an app with a differently signed build while keeping its data, permissions,
# installer and frozen state. Data is also saved to BACKUP_DIR before the uninstall.
# Usage: reinstall-keep-data.sh PACKAGE BACKUP_DIR APK [APK ...]
set -euo pipefail
pkg=$1 bak=$2; shift 2
a() { adb shell "$@" </dev/null; }
su_() { a "su -c '$1'"; }
mkdir -p "$bak"
installer=$(a "pm list packages -3 -i $pkg" | tr -d '\r' | grep "package:$pkg " | sed 's/.*installer=//')
disabled=$(a "pm list packages -d $pkg" | tr -d '\r' | grep -cx "package:$pkg" || true)
perms=$(a "dumpsys package $pkg" | sed -n '/runtime permissions:/,/^ *[a-z]* .*:$/p' | grep -oE '[a-zA-Z0-9_.]+: granted=true' | cut -d: -f1 | sort -u | tr '\n' ' ')
echo "$pkg: installer=$installer disabled=$disabled perms=[$perms]"
dirs="/data/data/$pkg /data/user_de/0/$pkg"
[ "$(su_ "[ -d /data/media/0/Android/data/$pkg ] && echo y")" = y ] && dirs="$dirs /data/media/0/Android/data/$pkg"
su_ "am force-stop $pkg"
# The phone writes the tar to stdout; exec-out keeps it binary-safe.
adb exec-out "su -c 'tar -cf - --exclude=$pkg/cache --exclude=$pkg/code_cache $dirs 2>/dev/null'" > "$bak/$pkg.tar"
echo "saved $(stat -c %s "$bak/$pkg.tar") bytes to $bak/$pkg.tar"
[ "$(stat -c %s "$bak/$pkg.tar")" -gt 10240 ] || { echo "backup suspiciously small, aborting"; exit 1; }
a "pm uninstall $pkg"
iopt=(); [ -n "$installer" ] && [ "$installer" != null ] && iopt=(-i "$installer")
adb install-multiple -r "${iopt[@]}" --bypass-low-target-sdk-block "$@"
uid=$(su_ "stat -c %u /data/data/$pkg")
cache_gid=$((uid - 10000 + 20000))
adb exec-in "su -c 'tar -xf - -C /'" < "$bak/$pkg.tar"
su_ "while pgrep -x tar >/dev/null; do sleep 0.3; done"
for d in /data/data/$pkg /data/user_de/0/$pkg; do
su_ "chown -R $uid:$uid $d; for c in cache code_cache; do mkdir -p $d/\$c; chown $uid:$cache_gid $d/\$c; chmod 2771 $d/\$c; done; chcon -hR \"\$(stat -c %C $d)\" $d"
done
case " $dirs " in *Android/data*)
su_ "d=/data/media/0/Android/data/$pkg; chown -R $uid:1078 \$d; find \$d -type d -exec chmod 2770 {} +; find \$d -type f -exec chmod 660 {} +; chcon -R u:object_r:media_rw_data_file:s0 \$d" ;;
esac
for p in $perms; do a "pm grant $pkg $p" 2>/dev/null || true; done
[ "$disabled" = 1 ] && su_ "pm disable-user --user 0 $pkg"
echo "$pkg: reinstalled as uid $uid, $(a "dumpsys package $pkg" | grep -m1 versionName | xargs)"