diff options
author | Aaron Ball <nullspoon@oper.io> | 2017-10-14 17:02:29 -0600 |
---|---|---|
committer | Aaron Ball <nullspoon@oper.io> | 2017-10-14 17:02:29 -0600 |
commit | 64b654a46aeb1aee4ee47d8c484a4346b9032e65 (patch) | |
tree | 069c07fbdc2dc33655d5858fcb836029fce619d1 | |
parent | 1d2569958f93d6989c4940cab1bf5263c18a5963 (diff) | |
download | andbackup-64b654a46aeb1aee4ee47d8c484a4346b9032e65.tar.gz andbackup-64b654a46aeb1aee4ee47d8c484a4346b9032e65.tar.xz |
backup_app:Add recovery mode support
Previously, this function was dependent on a running android system to
get application metadata (eg: data path, code path, etc). Now we assume
the defaults in global variables (can update them at a later date to be
more intelligent should android change the standard...again).
Now, the backup process uses POSIX shell compliant code to execute the
backup process, without using android system resources. This enables the
backup process to run while the system is in recover (eg: TWRP).
NOTE: This is currently dependent on TWRP being the recovery of choice,
as it checks for the presence of /sbin/twrp to determine if the system
is currently in recovery. Support for other recoveries (are there any
others?) can be added at a later date.
-rwxr-xr-x | andbackup.sh | 114 |
1 files changed, 80 insertions, 34 deletions
diff --git a/andbackup.sh b/andbackup.sh index 8df40a5..7f5c239 100755 --- a/andbackup.sh +++ b/andbackup.sh @@ -23,6 +23,10 @@ backups=/sdcard/andbackup #backups=/storage/ext_sd/bk/andbackup/andbackupBK flag_delimiter="-" +export ANDROID_DATA='/data/data' +export ANDROID_CODE='/data/app' +export ANDROID_SYSTEM='/system' + usage() { # NOTE: The maximum width of this text should be 65 chars. This # will ensure it displays properly on most devices without @@ -79,48 +83,50 @@ lfatal() { backup_app() { - local app=${1:-} + local app="${1}" - # Make sure app is specified - if [[ -z ${app} ]]; then - lerror "Please specify an app to backup." + if [ -z "${app}" ]; then + lerror "Application name required." return 1 fi #If app has the flag_delimiter that means options are passed in local preserveCache=false - if [[ 0 = $(echo ${app} | grep -q [${flag_delimiter}]; echo $?) ]]; then + if [ 0 = $(echo ${app} | grep -q [${flag_delimiter}]; echo $?) ]; then linfo "This app $app has passed in options" - if [[ 0 = $(echo ${app} | grep -q "preserveCache"; echo $?) ]]; then + if [ 0 = $(echo ${app} | grep -q "preserveCache"; echo $?) ]; then preserveCache=true fi #Need to get app back to std naming (without params) app=`echo ${app} | grep -o ^.*- | sed s/-//g | cat -` fi - + # Make sure app is installed - if [[ $(dumpsys package ${app} | wc -l) -eq 0 ]]; then + if [ ! -d "${ANDROID_DATA}/${app}" ]; then lerror "Package ${app} appears to not be installed." return 2 fi linfo "Backing up ${app}" + local apk="$(find ${ANDROID_CODE}/${app}-*/base.apk | head -n1)" + local data="${ANDROID_DATA}/${app}" - # Stop the application if it is running - am force-stop ${app} - - # Get pertinent metadata - local code=$(dumpsys package ${app} | grep codePath | cut -d'=' -f2 | head -n1) - local data=$(dumpsys package ${app} | grep dataDir | cut -d'=' -f2 | head -n1) - #linfo HERE is your data dir: $data + # No need to stop the application because we're in recovery mode # Create backup destination if not exist - [[ ! -d ${backups} ]] && mkdir -p ${backups} - [[ ! -d ${backups}/${app}/data ]] && mkdir -p ${backups}/${app}/data + [ ! -d "${backups}" ] && mkdir -p "${backups}" + # Delete data stage directory if it exists so we can start new + [ -d "${backups}/${app}/data" ] && rm -rf "${backups}/${app}/data" # Backup the apk file if it exists - if [[ -f ${code}/base.apk ]]; then - cp ${code}/base.apk ${backups}/${app}/base.apk + if [ ! -z "${apk}" ]; then + # Delete the old backup first + # There is a permissions issue querk when the backup was originall taken in + # recovery mode, but later is taken in android (Permission denied for no + # apparent reason) + [ -f "${backups}/${app}/base.apk" ] && rm -f "${backups}/${app}/base.apk" + # Copy the installer to the backup dir + cp -p "${apk}" "${backups}/${app}/base.apk" else linfo "${app} apk file could not be found. Skipping apk installer backup." fi @@ -129,16 +135,26 @@ backup_app() { # backup. This covers a weird edge case where an application is installed but # hasn't been launched (I think?). The data variable would be empty, causing # this script to backup /*. - if [ ! -d "${data:-}" ] || [ -z "${data:-}" ]; then + if [ -z "${data}" ] || [ ! -d "${data}" ]; then lwarn "No data directory for application '${app}' found. Skipping backup." return 2 fi + # Stop the application if it is running + # Don't try to stop it if the twrp binary is found. If we're in recovery + # mode, the application already isn't running. + if [ ! -f /sbin/twrp ]; then + linfo "Stopping application ${app}" + am force-stop "${app}" + else + linfo "Skipping application force stop while booted to recovery mode." + fi + # Copy the user data - cp -rp ${data}/* ${backups}/${app}/data/ + cp -rp "${data}" "${backups}/${app}/data" # Delete cache directory if it exists # This will sometimes free up significant amounts of space - if [[ ! -d "${backups}/${app}/data/cache" ]]; then + if [ ! -d "${backups}/${app}/data/cache" ]; then linfo "Cache doesn't exist for ${app}" elif ! $preserveCache; then linfo "Deleting cache for ${app}" @@ -149,13 +165,13 @@ backup_app() { # Compress the backup linfo "Compressing userdata for ${app}" - cd ${backups}/${app}/ + cd "${backups}/${app}/" tar -c data | gzip -c > data.tar.gz rm -rf data } -function list_apps { +list_apps() { pm list package | cut -d ':' -f 2 | sort } @@ -164,11 +180,19 @@ restore_app() { local app=${1:-} # Make sure app is specified - if [[ -z ${app} ]]; then + if [ -z "${app}" ]; then lerror "Please specify an app to restore." return 1 fi + # If twrp binary is found on the filesystem, do not attempt restore as + # restores cannot be done without a running system (the various android + # binaries don't work right). + if [ -f /sbin/twrp ]; then + printf "Cannot perform a %s while in recovery mode.\n" "${app}" + return 128 + fi + # When restoring something with flags need to restore app alone if [[ 0 = $(echo ${app} | grep -q [${flag_delimiter}]; echo $?) ]]; then linfo "This app $app had passed in options" @@ -221,37 +245,39 @@ restore_app() { backup_apps() { local apps=${@} - [[ -z ${apps[@]:-} ]] && lerror "At least one app is required." && return 1 + [ -z "${apps}" ] && lerror "At least one app is required." && return 1 - for app in ${apps[@]}; do - backup_app ${app} + IFS=' ' + for app in ${apps}; do + backup_app "${app}" done } restore_apps() { local apps=${@} - [[ -z ${apps[@]:-} ]] && log error "At least one app is required." && return 1 + [ -z "${apps}" ] && log error "At least one app is required.\n" && return 1 - for app in ${apps[@]}; do - restore_app ${app} + IFS=' ' + for app in ${apps}; do + restore_app "${app}" done } list_backup_apps() { local list=${1:-} - [[ -z ${list} ]] && printf "A backup list is required." && return 1 + [[ -z ${list} ]] && printf "A backup list is required.\n" && return 1 for app in $(cat ${list}); do - backup_app ${app} + backup_app "${app}" done } list_restore_apps() { local list=${1} - [[ -z ${list} ]] && printf "A backup list is required." && return 1 + [[ -z ${list} ]] && printf "A backup list is required.\n" && return 1 for app in $(cat ${list}); do restore_app ${app} @@ -259,6 +285,25 @@ list_restore_apps() { } +verify_system() { + if [ ! -d "${ANDROID_DATA}" ]; then + printf "Data directory (%s) not found.\n" ${ANDROID_DATA} >&2 + printf "Is it mounted?\n" >&2 + return 1 + fi + if [ ! -d "${ANDROID_CODE}" ]; then + printf "Application code directory (%s) not found.\n" ${ANDROID_CODE} >&2 + printf "Is it mounted?\n" >&2 + return 1 + fi + if [ ! -d "${ANDROID_SYSTEM}/etc" ]; then + printf "System partition (%s) is not mounted.\n" ${ANDROID_SYSTEM} >&2 + return 1 + fi + return 0 +} + + main() { local cmd=${1:-} shift @@ -269,6 +314,7 @@ main() { return 1 fi + verify_system || return 1 if [ "${cmd}" = 'backup' ]; then backup_apps ${@} |