blob: d9e017c2ad897b8dcd296e5489d3e559e6036a2b [file] [log] [blame]
#! /bin/bash
USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]
adb remount tests (overlayfs focus)
Conditions:
- Must be a userdebug build.
- Must be in adb mode.
- Kernel must have overlayfs enabled and patched to support override_creds.
- Must have either squashfs, ext4-dedupe or right-sized partitions.
- Minimum expectation system and vender are overlayfs covered partitions.
"
if [ X"${1}" = X"--help" -o X"${1}" = X"-h" -o X"${1}" = X"-?" ]; then
echo "${USAGE}" >&2
exit 0
fi
# Helper Variables
SPACE=" "
# A _real_ embedded tab character
TAB="`echo | tr '\n' '\t'`"
# A _real_ embedded escape character
ESCAPE="`echo | tr '\n' '\033'`"
GREEN="${ESCAPE}[38;5;40m"
RED="${ESCAPE}[38;5;196m"
ORANGE="${ESCAPE}[38;5;255:165:0m"
NORMAL="${ESCAPE}[0m"
# Helper functions
[ "USAGE: inFastboot
Returns: true if device is in fastboot mode" ]
inFastboot() {
fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
}
[ "USAGE: inAdb
Returns: true if device is in adb mode" ]
inAdb() {
adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
}
[ "USAGE: adb_sh <commands>
Returns: true if the command succeeded" ]
adb_sh() {
adb shell "${@}"
}
[ "USAGE: adb_date >/dev/stdout
Returns: report device epoch time (suitable for logcat -t)" ]
adb_date() {
adb_sh date +%s.%N </dev/null
}
[ "USAGE: adb_logcat [arguments] >/dev/stdout
Returns: the logcat output" ]
adb_logcat() {
echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
adb logcat "${@}" </dev/null |
grep -v 'logd : logdr: UID=' |
sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
}
[ "USAGE: get_property <prop>
Returns the property value" ]
get_property() {
adb_sh getprop ${1} </dev/null
}
[ "USAGE: isDebuggable
Returns: true if device is (likely) a debug build" ]
isDebuggable() {
if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
false
fi
}
[ "USAGE: adb_su <commands>
Returns: true if the command running as root succeeded" ]
adb_su() {
adb_sh su root "${@}"
}
[ "USAGE: adb_cat <file> >stdout
Returns: content of file to stdout with carriage returns skipped,
true of the file exists" ]
adb_cat() {
OUTPUT="`adb_sh cat ${1} </dev/null 2>&1`"
retval=${?}
echo "${OUTPUT}" | tr -d '\r'
return ${retval}
}
[ "USAGE: adb_reboot
Returns: true if the reboot command succeeded" ]
adb_reboot() {
adb reboot remount-test &&
sleep 2
}
[ "USAGE: adb_wait [timeout]
Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
else
adb wait-for-device
fi
}
[ "USAGE: fastboot_wait [timeout]
Returns: waits until the device has returned for fastboot or optional timeout" ]
fastboot_wait() {
# fastboot has no wait-for-device, but it does an automatic
# wait and requires (even a nonsensical) command to do so.
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
else
fastboot wait-for-device >/dev/null
fi >/dev/null 2>/dev/null ||
inFastboot
}
[ "USAGE: adb_root
Returns: true if device in root state" ]
adb_root() {
adb root >/dev/null </dev/null 2>/dev/null
sleep 2
adb_wait 2m &&
[ `adb_sh echo '${USER}'` = root ]
}
[ "USAGE: fastboot_getvar var expected
Returns: true if var output matches expected" ]
fastboot_getvar() {
O=`fastboot getvar ${1} 2>&1`
err=${?}
O="${O#< waiting for * >?}"
O="${O%%?Finished. Total time: *}"
if [ 0 -ne ${err} ]; then
echo ${O} >&2
false
return
fi
if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
echo "${2} != ${O}" >&2
false
return
fi
echo ${O} >&2
}
[ "USAGE: die [-t <epoch>] [message] >/dev/stderr
If -t <epoch> argument is supplied, dump logcat.
Returns: exit failure, report status" ]
die() {
if [ X"-t" = X"${1}" -a -n "${2}" ]; then
adb_logcat -b all -v nsec -t ${2} >&2
shift 2
fi
echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
exit 1
}
[ "USAGE: EXPECT_EQ <lval> <rval> [message]
Returns true if (regex) lval matches rval" ]
EXPECT_EQ() {
lval="${1}"
rval="${2}"
shift 2
if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
*}" ]; then
echo "ERROR: expected \"${lval}\"" >&2
echo " got \"${rval}\"" |
sed ': again
N
s/\(\n\)\([^ ]\)/\1 \2/
t again' >&2
if [ -n "${*}" ] ; then
echo " ${*}" >&2
fi
else
echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
fi
return 1
fi
if [ -n "${*}" ] ; then
if [ X"${lval}" != X"${rval}" ]; then
if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
echo "INFO: ok \"${lval}\"" >&2
echo " = \"${rval}\"" |
sed ': again
N
s/\(\n\)\([^ ]\)/\1 \2/
t again' >&2
if [ -n "${*}" ] ; then
echo " ${*}" >&2
fi
else
echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
fi
else
echo "INFO: ok \"${lval}\" ${*}" >&2
fi
fi
return 0
}
[ "USAGE: check_eq <lval> <rval> [message]
Exits if (regex) lval mismatches rval" ]
check_eq() {
left="${1}"
right="${2}"
shift 2
EXPECT_EQ "${left}" "${right}" ||
die "${@}"
}
[ "USAGE: skip_administrative_mounts < /proc/mounts
Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
skip_administrative_mounts() {
grep -v \
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
-e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
}
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
export ANDROID_SERIAL="${2}"
shift 2
fi
inFastboot && die "device in fastboot mode"
if ! inAdb; then
echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
adb_wait 2m
fi
inAdb || die "device not in adb mode"
isDebuggable || die "device not a debug build"
# Do something
adb_wait || die "wait for device failed"
adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
die "overlay module not present"
adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
die "overlay module can not be used on ANDROID"
adb_root ||
die "initial setup"
reboot=false
OVERLAYFS_BACKING="cache mnt/scratch"
for d in ${OVERLAYFS_BACKING}; do
if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, wiping" >&2
adb_sh rm -rf /${d}/overlay </dev/null ||
die "/${d}/overlay wipe"
reboot=true
fi
done
if ${reboot}; then
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m &&
adb_root ||
die "reboot after wipe"
fi
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
echo "${H}" &&
echo "${D}" &&
echo "${ORANGE}[ WARNING ]${NORMAL} overlays present before setup" >&2 ||
echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2
adb_sh df -k `adb_sh cat /proc/mounts |
skip_administrative_mounts |
cut -s -d' ' -f1`
T=`adb_date`
D=`adb disable-verity 2>&1`
err=${?}
echo "${D}"
if [ ${err} != 0 -o X"${D}" != X"${D##*setup failed}" ]; then
die -t ${T} "setup for overlay"
fi
if [ X"${D}" != X"${D##*using overlayfs}" ]; then
echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
fi
adb_reboot &&
adb_wait &&
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
echo "${H}" &&
echo "${D}" ||
die "overlay takeover failed"
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
T=`adb_date`
adb_root &&
adb remount &&
D=`adb_sh df -k </dev/null` ||
die -t ${T} "can not collect filesystem data"
if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
echo "${ORANGE}[ INFO ]${NORMAL} using scratch dynamic partition for overrides" >&2
H=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
[ -n "${H}" ] &&
echo "${ORANGE}[ INFO ]${NORMAL} scratch filesystem ${H}"
fi
for d in ${OVERLAYFS_BACKING}; do
if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
echo "${ORANGE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
fi
done
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
echo "${H}" &&
echo "${D}" &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay takeover after remount"
!(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
!(adb_sh grep " rw," /proc/mounts </dev/null | skip_administrative_mounts) ||
die "remount overlayfs missed a spot (ro)"
adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
skip_administrative_mounts |
grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
# Check something
A="Hello World! $(date)"
echo "${A}" | adb_sh "cat - > /system/hello"
echo "${A}" | adb_sh "cat - > /vendor/hello"
B="`adb_cat /system/hello`" ||
die "sytem hello"
check_eq "${A}" "${B}" system before reboot
B="`adb_cat /vendor/hello`" ||
die "vendor hello"
check_eq "${A}" "${B}" vendor before reboot
adb_reboot &&
adb_wait &&
B="`adb_cat /system/hello`" ||
die "re-read system hello after reboot"
check_eq "${A}" "${B}" system after reboot
# Only root can read vendor if sepolicy permissions are as expected
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after reboot w/o root"
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
adb_root &&
B="`adb_cat /vendor/hello`" ||
die "re-read vendor hello after reboot"
check_eq "${A}" "${B}" vendor after reboot
adb reboot-fastboot &&
fastboot_wait 2m &&
fastboot flash vendor ||
die "fastbootd flash vendor"
# check scratch via fastboot
fastboot_getvar partition-type:scratch raw &&
fastboot_getvar has-slot:scratch no &&
fastboot_getvar is-logical:scratch yes ||
die "fastboot can not see scratch parameters"
echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
fastboot erase scratch &&
die "fastbootd can erase scratch"
echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot format scratch to fail" >&2
fastboot format scratch &&
die "fastbootd can format scratch"
fastboot reboot ||
die "can not reboot out of fastbootd"
echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
adb_wait 2m ||
die "did not reboot after flash"
adb_root &&
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` &&
echo "${H}" &&
echo "${D}" &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay system takeover after flash vendor"
echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
die "overlay minus vendor takeover after flash vendor"
B="`adb_cat /system/hello`" ||
die "re-read system hello after flash vendor"
check_eq "${A}" "${B}" system after flash vendor
adb_root ||
die "adb root"
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after flash vendor"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
T=`adb_date`
adb remount &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
adb_sh rm /system/hello </dev/null ||
die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`" &&
die "re-read system hello after rm"
check_eq "cat: /system/hello: No such file or directory" "${B}" after flash rm
B="`adb_cat /vendor/hello`" &&
die "re-read vendor hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
adb reboot-fastboot &&
dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
fastboot_wait 2m ||
die "reboot into fastbootd"
fastboot flash scratch adb-remount-test.img
err=${?}
rm adb-remount-test.img
[ 0 -eq ${err} ] ||
die "fastbootd flash scratch"
fastboot reboot ||
die "can not reboot out of fastbootd"
adb_wait 2m &&
adb_root ||
die "did not reboot after flash"
T=`adb_date`
D=`adb disable-verity 2>&1`
err=${?}
echo "${D}"
[ ${err} = 0 ] &&
[ X"${D}" = X"${D##*setup failed}" ] &&
[ X"${D}" != X"${D##*using overlayfs}" ] ||
die -t ${T} "setup for overlayfs"
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2