fs_mgr: overlayfs support legacy devices (marlin)
Expand the tests to deal with the boot environment for marlin.
Recognize that older overlayfs drivers do not report to /sys/module
and the parsing /proc/filesystem is another place to interrogate this.
Suppress adb push and pull noise during testing. Resolve APEX
failures. Add some cleanup to test script.
NB: Running test to completion is difficult because marlin's USB
driver is flakey enough through the multitude of reboots and
may not reconnect. The tester will have to notice when a reboot
is stalling and manually disconnect and reconnect the USB
connection to trigger discovery and to continue through the
test sequences. To make this easier, report when we are
waiting for the device to make it easier to babysit.
Test: system/core/fs_mgr/tests/adb-remount-test.sh
Bug: 120448575
Bug: 123079041
Change-Id: I5fc5f01b4e4788ac57541cb5235f7ac4e4284d71
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index c7d2cb9..0c2b3d3 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -67,6 +67,13 @@
return ret;
}
+// determine if a filesystem is available
+bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) {
+ std::string filesystems;
+ if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false;
+ return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
+}
+
} // namespace
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
@@ -625,8 +632,12 @@
// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
- if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
- if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
+ if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) {
+ return "f2fs";
+ }
+ if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) {
+ return "ext4";
+ }
return "auto";
}
@@ -657,7 +668,7 @@
if (mnt_type == "f2fs") {
command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint);
} else if (mnt_type == "ext4") {
- command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
+ command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
} else {
errno = ESRCH;
LERROR << mnt_type << " has no mkfs cookbook";
@@ -1002,7 +1013,7 @@
if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
return OverlayfsValidResult::kOverrideCredsRequired;
}
- if (!fs_mgr_access("/sys/module/overlay")) {
+ if (!fs_mgr_overlayfs_filesystem_available("overlay")) {
return OverlayfsValidResult::kNotSupported;
}
struct utsname uts;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 4d9bc61..8298bf2 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1,4 +1,15 @@
#! /bin/bash
+#
+# Divided into four section:
+#
+## USAGE
+## Helper Variables
+## Helper Functions
+## MAINLINE
+
+##
+## USAGE
+##
USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]
@@ -17,20 +28,26 @@
exit 0
fi
-# Helper Variables
+##
+## Helper Variables
+##
SPACE=" "
# A _real_ embedded tab character
TAB="`echo | tr '\n' '\t'`"
# A _real_ embedded escape character
ESCAPE="`echo | tr '\n' '\033'`"
+# A _real_ embedded carriage return character
+CR="`echo | tr '\n' '\r'`"
GREEN="${ESCAPE}[38;5;40m"
RED="${ESCAPE}[38;5;196m"
ORANGE="${ESCAPE}[38;5;255:165:0m"
BLUE="${ESCAPE}[35m"
NORMAL="${ESCAPE}[0m"
-# Helper functions
+##
+## Helper Functions
+##
[ "USAGE: inFastboot
@@ -68,6 +85,8 @@
args="${args}${i}"
elif [ X"${i}" != X"${i#* }" ]; then
args="${args}'${i}'"
+ elif [ X"${i}" != X"${i#*${TAB}}" ]; then
+ args="${args}'${i}'"
else
args="${args}${i}"
fi
@@ -130,16 +149,62 @@
Returns: true if the reboot command succeeded" ]
adb_reboot() {
- adb reboot remount-test &&
+ adb reboot remount-test || true
sleep 2
}
+[ "USAGE: format_duration [<seconds>|<seconds>s|<minutes>m|<hours>h|<days>d]
+
+human readable output whole seconds, whole minutes or mm:ss" ]
+format_duration() {
+ if [ -z "${1}" ]; then
+ echo unknown
+ return
+ fi
+ duration="${1}"
+ if [ X"${duration}" != X"${duration%s}" ]; then
+ duration=${duration%s}
+ elif [ X"${duration}" != X"${duration%m}" ]; then
+ duration=`expr ${duration%m} \* 60`
+ elif [ X"${duration}" != X"${duration%h}" ]; then
+ duration=`expr ${duration%h} \* 3600`
+ elif [ X"${duration}" != X"${duration%d}" ]; then
+ duration=`expr ${duration%d} \* 86400`
+ fi
+ seconds=`expr ${duration} % 60`
+ minutes=`expr \( ${duration} / 60 \) % 60`
+ hours=`expr ${duration} / 3600`
+ if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
+ if [ 1 -eq ${duration} ]; then
+ echo 1 second
+ return
+ fi
+ echo ${duration} seconds
+ return
+ elif [ 60 -eq ${duration} ]; then
+ echo 1 minute
+ return
+ elif [ 0 -eq ${seconds} -a 0 -eq ${hours} ]; then
+ echo ${minutes} minutes
+ return
+ fi
+ if [ 0 -eq ${hours} ]; then
+ echo ${minutes}:`expr ${seconds} / 10``expr ${seconds} % 10`
+ return
+ fi
+ echo ${hours}:`expr ${minutes} / 10``expr ${minutes} % 10`:`expr ${seconds} / 10``expr ${seconds} % 10`
+}
+
[ "USAGE: adb_wait [timeout]
Returns: waits until the device has returned for adb or optional timeout" ]
adb_wait() {
if [ -n "${1}" ]; then
+ echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
+ retval=${?}
+ echo -n " ${CR}"
+ return ${retval}
else
adb wait-for-device
fi
@@ -152,10 +217,14 @@
# 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
+ echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} "${CR}"
+ timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null
+ retval=${?}
+ echo -n " ${CR}"
+ ( exit ${retval} )
else
- fastboot wait-for-device >/dev/null
- fi >/dev/null 2>/dev/null ||
+ fastboot wait-for-device >/dev/null 2>/dev/null
+ fi ||
inFastboot
}
@@ -310,9 +379,14 @@
-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 "^rootfs / rootfs rw," \
-e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
}
+##
+## MAINLINE
+##
+
if [ X"-s" = X"${1}" -a -n "${2}" ]; then
export ANDROID_SERIAL="${2}"
shift 2
@@ -320,7 +394,7 @@
inFastboot && die "device in fastboot mode"
if ! inAdb; then
- echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
+ echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode"
adb_wait 2m
fi
inAdb || die "specified device not in adb mode"
@@ -331,19 +405,38 @@
enforcing=false
fi
-# Do something
+# Do something.
D=`get_property ro.serialno`
[ -n "${D}" ] || D=`get_property ro.boot.serialno`
[ -z "${D}" ] || ANDROID_SERIAL=${D}
+USB_SERIAL=
+[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
+ grep usb |
+ xargs grep -l ${ANDROID_SERIAL}`
+USB_ADDRESS=
+if [ -n "${USB_SERIAL}" ]; then
+ USB_ADDRESS=${USB_SERIAL%/serial}
+ USB_ADDRESS=usb${USB_ADDRESS##*/}
+fi
+[ -z "${ANDROID_SERIAL}${USB_ADDRESS}" ] ||
+ echo "${BLUE}[ INFO ]${NORMAL}" ${ANDROID_SERIAL} ${USB_ADDRESS} >&2
BUILD_DESCRIPTION=`get_property ro.build.description`
-echo "${BLUE}[ INFO ]${NORMAL} ${ANDROID_SERIAL} ${BUILD_DESCRIPTION}" >&2
+[ -z "${BUILD_DESCRIPTION}" ] ||
+ echo "${BLUE}[ INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2
+
+VERITY_WAS_ENABLED=false
+if [ "orange" = "`get_property ro.boot.verifiedbootstate`" -a \
+ "2" = "`get_property partition.system.verified`" ]; then
+ VERITY_WAS_ENABLED=true
+fi
echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
overlayfs_supported=true;
adb_wait || die "wait for device failed"
-adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
+adb_sh ls -d /sys/module/overlay </dev/null >/dev/null 2>/dev/null ||
+ adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
(
echo "${ORANGE}[ WARNING ]${NORMAL} overlay module not present" >&2 &&
@@ -391,9 +484,9 @@
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot after wipe"
+ die "lost device after reboot after wipe (USB stack broken?)"
adb_root ||
- die "lost device after elevation to root after wipe"
+ die "lost device after elevation to root after wipe (USB stack broken?)"
fi
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
@@ -455,9 +548,9 @@
L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot requested"
+ die "lost device after reboot requested (USB stack broken?)"
adb_root ||
- die "lost device after elevation to root"
+ die "lost device after elevation to root (USB stack broken?)"
rebooted=true
# re-disable verity to see the setup remarks expected
T=`adb_date`
@@ -544,7 +637,7 @@
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
die "overlay takeover after remount"
!(adb_sh grep "^overlay " /proc/mounts </dev/null |
- grep -v "^overlay /\(vendor\|system\)/..* overlay ro," |
+ grep -v "^overlay /\(vendor\|system\|bionic\)/..* overlay ro," |
grep " overlay ro,") &&
!(adb_sh grep " rw," /proc/mounts </dev/null |
skip_administrative_mounts data) ||
@@ -555,7 +648,7 @@
fi
fi
-# Check something
+# Check something.
echo "${GREEN}[ RUN ]${NORMAL} push content to /system and /vendor" >&2
@@ -569,17 +662,22 @@
die "vendor hello"
check_eq "${A}" "${B}" /vendor before reboot
-# download libc.so, append some gargage, push back, and check if the file is updated.
+# Download libc.so, append some gargage, push back, and check if the file
+# is updated.
tempdir="`mktemp -d`"
cleanup() {
rm -rf ${tempdir}
}
-adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir} >/dev/null ||
+ die "pull libc.so from device"
garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
echo ${garbage} >> ${tempdir}/libc.so
-adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
-adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
-diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so >/dev/null ||
+ die "push libc.so to device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
+ die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null ||
+ die "libc.so differ"
echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
@@ -605,7 +703,7 @@
die "re-read /system/hello after reboot"
check_eq "${A}" "${B}" /system after reboot
echo "${GREEN}[ OK ]${NORMAL} /system content remains after reboot" >&2
-# Only root can read vendor if sepolicy permissions are as expected
+# Only root can read vendor if sepolicy permissions are as expected.
if ${enforcing}; then
adb_unroot
B="`adb_cat /vendor/hello`" &&
@@ -619,9 +717,9 @@
check_eq "${A}" "${B}" vendor after reboot
echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2
-# check if the updated libc.so is persistent after reboot
+# Check if the updated libc.so is persistent after reboot.
adb_root &&
- adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
+ adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice >/dev/null ||
die "pull libc.so from device"
diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
rm -r ${tempdir}
@@ -677,7 +775,7 @@
fi
fastboot reboot ||
die "can not reboot out of fastboot"
- echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot"
adb_wait 2m ||
die "did not reboot after flash"
if ${overlayfs_needed}; then
@@ -719,9 +817,26 @@
echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
T=`adb_date`
-adb remount &&
+H=`adb remount 2>&1`
+err=${?}
+L=
+D="${H%?Now reboot your device for settings to take effect}"
+if [ X"${H}" != X"${D}" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)"
+ L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
+ adb_reboot &&
+ adb_wait 2m &&
+ adb_root ||
+ die "failed to reboot"
+ T=`adb_date`
+ H=`adb remount 2>&1`
+ err=${?}
+fi
+echo "${H}"
+[ ${err} = 0 ] &&
( adb_sh rm /vendor/hello </dev/null 2>/dev/null || true ) &&
adb_sh rm /system/hello </dev/null ||
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
die -t ${T} "cleanup hello"
B="`adb_cat /system/hello`" &&
die "re-read /system/hello after rm"
@@ -768,12 +883,12 @@
die -t ${T} "setup for overlayfs"
fi
-echo "${GREEN}[ RUN ]${NORMAL} test raw remount command" >&2
+echo "${GREEN}[ RUN ]${NORMAL} test raw remount commands" >&2
-# prerequisite is a prepped device from above
+# Prerequisite is a prepped device from above.
adb_reboot &&
adb_wait 2m ||
- die "lost device after reboot to ro state"
+ die "lost device after reboot to ro state (USB stack broken?)"
adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null &&
die "/vendor is not read-only"
adb_su mount -o rw,remount /vendor ||
@@ -782,4 +897,12 @@
die "/vendor is not read-write"
echo "${GREEN}[ OK ]${NORMAL} mount -o rw,remount command works" >&2
+if $VERITY_WAS_ENABLED && $overlayfs_supported; then
+ adb_root &&
+ adb enable-verity &&
+ adb_reboot &&
+ adb_wait 2m ||
+ die "failed to restore verity" >&2
+fi
+
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2