#!/bin/sh
# adb_backup.sh
# 2026-02-14
# by Gernot Walzl
# Backup and restore data of Android apps.
# ADB root debugging is required. Tested on Android 15.
set -e
CWD=$(pwd)
TMP=${TMP:-'/var/tmp'}
USER_ID=${USER_ID:-'0'}
print_usage () {
echo "Usage: $0 {list|backup PACKAGE|restore FILENAME}"
echo "Example: $0 backup org.videolan.vlc"
echo "Example: $0 restore org.videolan.vlc_2026-01-31.zip"
}
list () {
adb shell "pm list package -3 | sed 's/^package://' | sort"
}
backup () {
PKG="$1"
adb root
adb shell "test -d 'data/data/$PKG'" || return 1
echo
echo "Backing up $PKG:"
mkdir -p "$TMP/$PKG"
cd "$TMP/$PKG" || return 1
echo "/data/data/$PKG"
adb exec-out "tar -cz 'data/data/$PKG' \
2> /dev/null" \
> "${PKG}_data.tar.gz"
adb shell "find 'data/data/$PKG' -type f -exec sha256sum '{}' \;" \
> "${PKG}_data.sha256"
DIRS=$(adb shell "cd '/storage/emulated/$USER_ID' \
&& find Android -type d -name '$PKG'")
for DIR in $DIRS; do
echo "/storage/emulated/$USER_ID/$DIR"
ARCHNAME="${PKG}_$(dirname "$DIR" | tr / _)"
adb exec-out "tar -cz -C '/storage/emulated/$USER_ID' '$DIR' \
2> /dev/null" \
> "${ARCHNAME}.tar.gz"
adb shell "cd '/storage/emulated/$USER_ID' \
&& find '$DIR' -type f -exec sha256sum '{}' \;" \
> "${ARCHNAME}.sha256"
done
PKGPATHS=$(adb shell "pm path '$PKG' | sed 's/^package://'")
for PKGPATH in $PKGPATHS; do
echo "$PKGPATH"
adb pull "$PKGPATH" \
> /dev/null
BASENAME=$(basename "$PKGPATH")
mv "$BASENAME" "${PKG}_${BASENAME}"
done
ZIPFILE="${PKG}_$(date +%Y-%m-%d).zip"
echo
echo "Creating $ZIPFILE:"
zip -r "$CWD/$ZIPFILE" .
cd "$CWD"
rm -rf "$TMP/$PKG"
}
restore () {
FILENAME=$(realpath "$1")
adb root
PKG=$(unzip -l "$FILENAME" \
| sed -n '/_Android_/d;s/.* \(.*\)_data.tar.gz$/\1/p')
if [ -z "$PKG" ]; then
return 1
fi
echo
mkdir -p "$TMP/$PKG"
cd "$TMP/$PKG" || return 1
unzip "$FILENAME"
echo
echo "Restoring $1:"
for APK in *.apk; do
echo "$APK"
adb install "$APK"
done
USER_APP=$(adb shell "stat -c '%U' '/data/data/$PKG'")
for ARCHIVE in *_Android_*.tar.gz; do
echo "$ARCHIVE"
cat "$ARCHIVE" \
| adb shell "tar -xzf - -C '/storage/emulated/$USER_ID'"
done
adb shell "cd '/storage/emulated/$USER_ID' \
&& find Android -type d -name '$PKG' -exec chown -R '$USER_APP' '{}' \;"
echo "${PKG}_data.tar.gz"
cat "${PKG}_data.tar.gz" \
| adb shell "tar -xzf -"
adb shell "chown -R '${USER_APP}:${USER_APP}' \
'/data/data/$PKG'"
adb shell "chown -R '${USER_APP}:${USER_APP}_cache' \
'/data/data/$PKG/cache' \
'/data/data/$PKG/code_cache'"
adb shell "restorecon -DR '/data/data/$PKG'"
echo
echo "Checking restored data:"
for CHECKSUMS in *_Android_*.sha256; do
echo "$CHECKSUMS"
if [ -s "$CHECKSUMS" ]; then
cat "$CHECKSUMS" \
| adb shell "cd '/storage/emulated/$USER_ID' \
&& sha256sum -cs -" \
|| echo "ERROR: 'sha256sum -c $CHECKSUMS' failed!"
fi
done
echo "${PKG}_data.sha256"
cat "${PKG}_data.sha256" \
| adb shell "sha256sum -cs -" \
|| echo "ERROR: 'sha256sum -c ${PKG}_data.sha256' failed!"
cd "$CWD"
rm -rf "$TMP/$PKG"
}
case "$1" in
'list')
list
;;
'backup')
backup "$2"
;;
'restore')
restore "$2"
;;
*)
print_usage
esac