Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d109ecb authored by Mark Salyzyn's avatar Mark Salyzyn
Browse files

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
parent bece53e5
Loading
Loading
Loading
Loading
+15 −4
Original line number Diff line number Diff line
@@ -67,6 +67,13 @@ bool fs_mgr_access(const std::string& path) {
    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 @@ const std::string kMkExt4("/system/bin/mke2fs");

// 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 @@ bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std:
    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 @@ OverlayfsValidResult fs_mgr_overlayfs_valid() {
    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;
+152 −29
Original line number Diff line number Diff line
#! /bin/bash
#
# Divided into four section:
#
##  USAGE
##  Helper Variables
##  Helper Functions
##  MAINLINE

##
##  USAGE
##

USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]

@@ -17,20 +28,26 @@ if [ X"${1}" = X"--help" -o X"${1}" = X"-h" -o X"${1}" = X"-?" ]; then
  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 @@ adb_sh() {
      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 @@ adb_cat() {

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_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
    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 @@ skip_administrative_mounts() {
    -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 @@ fi

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 @@ if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
  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 @@ if ${reboot}; then
  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 @@ if [ X"${D}" != X"${H}" ]; then
  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 @@ if ${overlayfs_needed}; then
    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 @@ else
  fi
fi

# Check something
# Check something.

echo "${GREEN}[ RUN      ]${NORMAL} push content to /system and /vendor" >&2

@@ -569,17 +662,22 @@ B="`adb_cat /vendor/hello`" ||
  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 @@ B="`adb_cat /system/hello`" ||
  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 @@ adb_root &&
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 @@ else
  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 @@ fi
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 @@ if [ -n "${scratch_partition}" ]; then
    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 @@ adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null ||
  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