From 4a049b563c758755529cd3b858262db52b2f6e83 Mon Sep 17 00:00:00 2001 From: Dan Pasanen Date: Mon, 16 Jan 2017 19:26:50 -0600 Subject: [PATCH] vendor: add custom backuptools and postinstall script for A/B OTAs * A/B OTA devices wont run backuptools in recovery (because they don't go in to recovery to do an OTA). In these cases let's use a modified version to backup/restore from within android upon postinstall. * Add backuptool_postinstall.sh which will be run prior to the normal postinstall script in order to backup/restore via addon.d scripts. * This needs to be done in such a manner because we need /postinstall mounted rw instead of the ro with context= options which are used for the normal postinstall (dexopt) script. Change-Id: I51511870634dd1ec5388adafddb446f95cc5a950 --- config/common.mk | 7 + prebuilt/common/bin/backuptool_ab.functions | 51 +++++++ prebuilt/common/bin/backuptool_ab.sh | 124 ++++++++++++++++++ prebuilt/common/bin/backuptool_postinstall.sh | 11 ++ 4 files changed, 193 insertions(+) create mode 100644 prebuilt/common/bin/backuptool_ab.functions create mode 100755 prebuilt/common/bin/backuptool_ab.sh create mode 100755 prebuilt/common/bin/backuptool_postinstall.sh diff --git a/config/common.mk b/config/common.mk index a5b35320..8d17bb1b 100644 --- a/config/common.mk +++ b/config/common.mk @@ -46,6 +46,13 @@ PRODUCT_COPY_FILES += \ vendor/lineage/prebuilt/common/bin/50-lineage.sh:system/addon.d/50-lineage.sh \ vendor/lineage/prebuilt/common/bin/blacklist:system/addon.d/blacklist +ifeq ($(AB_OTA_UPDATER),true) +PRODUCT_COPY_FILES += \ + vendor/lineage/prebuilt/common/bin/backuptool_ab.sh:system/bin/backuptool_ab.sh \ + vendor/lineage/prebuilt/common/bin/backuptool_ab.functions:system/bin/backuptool_ab.functions \ + vendor/lineage/prebuilt/common/bin/backuptool_postinstall.sh:system/bin/backuptool_postinstall.sh +endif + # Backup Services whitelist PRODUCT_COPY_FILES += \ vendor/lineage/config/permissions/backup.xml:system/etc/sysconfig/backup.xml diff --git a/prebuilt/common/bin/backuptool_ab.functions b/prebuilt/common/bin/backuptool_ab.functions new file mode 100644 index 00000000..ffb246f0 --- /dev/null +++ b/prebuilt/common/bin/backuptool_ab.functions @@ -0,0 +1,51 @@ +#!/system/bin/sh +# +# Functions for backuptool_ab.sh +# + +export S=/system +export C=/postinstall/tmp/backupdir +export V=15.1 +export backuptool_ab=true + +copy_file() { + # toybox's cp doesn't do directories correctly for whatever reason + mkdir -p `dirname $2` + + cp -dp "$1" "$2" + # symlinks don't have a context + if [ ! -L "$1" ]; then + # it is assumed that every label starts with 'u:object_r' and has no white-spaces + local context=`ls -Z "$1" | grep -o 'u:object_r:[^ ]*' | head -1` + chcon "$context" "$2" + fi +} + +backup_file() { + if [ -e "$1" -o -L "$1" ]; then + local FILE=`basename "$1"` + local DIR=`dirname "$1"` + # dont backup any apps that have odex files, they are useless + if ( echo "$FILE" | grep -q "\.apk$" ) && [ -e `echo "$1" | sed -e 's/\.apk$/\.odex/'` ]; then + echo "Skipping odexed apk $1"; + else + mkdir -p "$C/$DIR" + copy_file "$1" "$C/$DIR/$FILE" + fi + fi +} + +restore_file() { + local FILE=`basename "$1"` + local DIR=`dirname "$1"` + if [ -e "$C/$DIR/$FILE" -o -L "$C/$DIR/$FILE" ]; then + if [ ! -d "/postinstall/$DIR" ]; then + mkdir -p "/postinstall/$DIR"; + fi + copy_file "$C/$DIR/$FILE" "/postinstall/$1"; + if [ -n "$2" ]; then + echo "Deleting obsolete file $2" + rm "$2"; + fi + fi +} diff --git a/prebuilt/common/bin/backuptool_ab.sh b/prebuilt/common/bin/backuptool_ab.sh new file mode 100755 index 00000000..26034a4d --- /dev/null +++ b/prebuilt/common/bin/backuptool_ab.sh @@ -0,0 +1,124 @@ +#!/system/bin/sh +# +# Backup and restore addon /system files +# + +export S=/system +export C=/postinstall/tmp/backupdir +export V=15.1 + +# Scripts in /system/addon.d expect to find backuptool.functions in /tmp +mkdir -p /postinstall/tmp/ +cp -f /postinstall/system/bin/backuptool_ab.functions /postinstall/tmp/backuptool.functions + +# Preserve /system/addon.d in /tmp/addon.d +preserve_addon_d() { + if [ -d /system/addon.d/ ]; then + mkdir -p /postinstall/tmp/addon.d/ + cp -a /system/addon.d/* /postinstall/tmp/addon.d/ + chmod 755 /postinstall/tmp/addon.d/*.sh + fi +} + +# Restore /postinstall/system/addon.d from /postinstall/tmp/addon.d +restore_addon_d() { + if [ -d /postinstall/tmp/addon.d/ ]; then + mkdir -p /postinstall/system/addon.d/ + cp -a /postinstall/tmp/addon.d/* /postinstall/system/addon.d/ + rm -rf /postinstall/tmp/addon.d/ + fi +} + +# Proceed only if /system is the expected major and minor version +check_prereq() { +# If there is no build.prop file the partition is probably empty. +if [ ! -r /system/build.prop ]; then + return 0 +fi + +grep -q "^ro.lineage.version=$V.*" /system/etc/prop.default /system/build.prop && return 1 + +echo "Not backing up files from incompatible version: $V" +return 0 +} + +check_blacklist() { + if [ -f /system/addon.d/blacklist -a -d /$1/addon.d/ ]; then + ## Discard any known bad backup scripts + cd /$1/addon.d/ + for f in *sh; do + [ -f $f ] || continue + s=$(md5sum $f | cut -c-32) + grep -q $s /system/addon.d/blacklist && rm -f $f + done + fi +} + +check_whitelist() { + found=0 + if [ -f /system/addon.d/whitelist ];then + ## forcefully keep any version-independent stuff + cd /$1/addon.d/ + for f in *sh; do + s=$(md5sum $f | cut -c-32) + grep -q $s /system/addon.d/whitelist + if [ $? -eq 0 ]; then + found=1 + else + rm -f $f + fi + done + fi + return $found +} + +# Execute /system/addon.d/*.sh scripts with $1 parameter +run_stage() { +if [ -d /postinstall/tmp/addon.d/ ]; then + for script in $(find /postinstall/tmp/addon.d/ -name '*.sh' |sort -n); do + # we have no /sbin/sh in android, only recovery + # use /system/bin/sh here instead + sed -i '0,/#!\/sbin\/sh/{s|#!/sbin/sh|#!/system/bin/sh|}' $script + # we can't count on /tmp existing on an A/B device, so utilize /postinstall/tmp + # as a pseudo-/tmp dir + sed -i 's|. /tmp/backuptool.functions|. /postinstall/tmp/backuptool.functions|g' $script + $script $1 + done +fi +} + +case "$1" in + backup) + mkdir -p $C + if check_prereq; then + if check_whitelist postinstall/system; then + exit 127 + fi + fi + check_blacklist postinstall/system + preserve_addon_d + run_stage pre-backup + run_stage backup + run_stage post-backup + ;; + restore) + if check_prereq; then + if check_whitelist postinstall/tmp; then + exit 127 + fi + fi + check_blacklist postinstall/tmp + run_stage pre-restore + run_stage restore + run_stage post-restore + restore_addon_d + rm -rf $C + rm -rf /postinstall/tmp + sync + ;; + *) + echo "Usage: $0 {backup|restore}" + exit 1 +esac + +exit 0 diff --git a/prebuilt/common/bin/backuptool_postinstall.sh b/prebuilt/common/bin/backuptool_postinstall.sh new file mode 100755 index 00000000..eef04098 --- /dev/null +++ b/prebuilt/common/bin/backuptool_postinstall.sh @@ -0,0 +1,11 @@ +#!/system/bin/sh +# +# LineageOS A/B OTA Postinstall Script +# + +/postinstall/system/bin/backuptool_ab.sh backup +/postinstall/system/bin/backuptool_ab.sh restore + +sync + +exit 0