Merge "fs_mgr: overlayfs support legacy devices (marlin)" am: 4e3a5f61a4
am: 694af77137

Change-Id: I1943fe756f0c8c9ca624008a12a3bc34a05adf0a
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