Merge "Do not remove speculative frames in all cases."
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f00983a..e761e56 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -53,6 +53,7 @@
     int file_names_mode = 0;
     off64_t erase_blk_size = 0;
     off64_t logical_blk_size = 0;
+    std::string vbmeta_partition;
 };
 
 struct flag_list {
@@ -97,6 +98,7 @@
         {"verifyatboot", MF_VERIFYATBOOT},
         {"verify", MF_VERIFY},
         {"avb", MF_AVB},
+        {"avb=", MF_AVB},
         {"noemulatedsd", MF_NOEMULATEDSD},
         {"notrim", MF_NOTRIM},
         {"formattable", MF_FORMATTABLE},
@@ -314,6 +316,8 @@
                     flag_vals->swap_prio = strtoll(arg, NULL, 0);
                 } else if (flag == MF_MAX_COMP_STREAMS) {
                     flag_vals->max_comp_streams = strtoll(arg, NULL, 0);
+                } else if (flag == MF_AVB) {
+                    flag_vals->vbmeta_partition = arg;
                 } else if (flag == MF_ZRAMSIZE) {
                     auto is_percent = !!strrchr(arg, '%');
                     auto val = strtoll(arg, NULL, 0);
@@ -583,6 +587,7 @@
         entry.erase_blk_size = flag_vals.erase_blk_size;
         entry.logical_blk_size = flag_vals.logical_blk_size;
         entry.sysfs_path = std::move(flag_vals.sysfs_path);
+        entry.vbmeta_partition = std::move(flag_vals.vbmeta_partition);
         if (entry.fs_mgr_flags.logical) {
             entry.logical_partition_name = entry.blk_device;
         }
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ef043f9..8bfcd81 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -144,7 +144,10 @@
     if (entry->fs_mgr_flags.logical) {
         fs_mgr_update_logical_partition(entry);
     }
-    return fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
+    auto save_errno = errno;
+    auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
+    errno = save_errno;
+    return has_shared_blocks;
 }
 
 bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
@@ -263,8 +266,10 @@
 
 std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
     std::vector<std::string> ret;
+    auto save_errno = errno;
     fs_mgr_update_verity_state(
             [&ret](const std::string& mount_point, int) { ret.emplace_back(mount_point); });
+    if ((errno == ENOENT) || (errno == ENXIO)) errno = save_errno;
     return ret;
 }
 
@@ -837,10 +842,12 @@
         return ret;
     }
 
+    auto save_errno = errno;
     Fstab fstab;
     if (!ReadDefaultFstab(&fstab)) {
         return false;
     }
+    errno = save_errno;
     auto mounts = fs_mgr_candidate_list(&fstab, fs_mgr_mount_point(mount_point));
     if (mounts.empty()) return ret;
 
@@ -864,7 +871,8 @@
         break;
     }
     if (dir.empty()) {
-        errno = ESRCH;
+        if (change && *change) errno = ESRCH;
+        if (errno == EPERM) errno = save_errno;
         return ret;
     }
 
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 26a1e5c..d9a5e0a 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -118,6 +118,7 @@
     off64_t erase_blk_size = 0;
     off64_t logical_blk_size = 0;
     std::string sysfs_path;
+    std::string vbmeta_partition;
 
     // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
     // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 561debb..fde82b4 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -46,7 +46,7 @@
   adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
 }
 
-[ "USAGE: adb_sh <commands>
+[ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
 
 Returns: true if the command succeeded" ]
 adb_sh() {
@@ -86,7 +86,7 @@
   fi
 }
 
-[ "USAGE: adb_su <commands>
+[ "USAGE: adb_su <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
 
 Returns: true if the command running as root succeeded" ]
 adb_su() {
@@ -284,23 +284,47 @@
 
 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 &&
   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"
+  (
+    echo "${ORANGE}[  WARNING ]${NORMAL} overlay module not present" >&2 &&
+      false
+  ) ||
+  overlayfs_supported=false
+if ${overlayfs_supported}; then
+  case `adb_sh uname -r </dev/null` in
+    4.[6789].* | 4.[1-9][0-9]* | [56789].*)
+      adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
+        echo "${GREEN}[       OK ]${NORMAL} overlay module supports override_creds" >&2 ||
+        (
+          echo "${ORANGE}[  WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
+          false
+        ) ||
+        overlayfs_supported=false;
+      ;;
+    *)
+      echo "${GREEN}[       OK ]${NORMAL} overlay module uses callers creds" >&2
+      ;;
+  esac
+fi
+
 adb_root ||
   die "initial setup"
 
 echo "${GREEN}[ RUN      ]${NORMAL} Checking current overlayfs status" >&2
 
+# We can not universally use adb enable-verity to ensure device is
+# in a overlayfs disabled state since it can prevent reboot on
+# devices that remount the physical content rather than overlayfs.
+# So lets do our best to surgically wipe the overlayfs state without
+# having to go through enable-verity transition.
 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
+    echo "${ORANGE}[  WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
     adb_sh rm -rf /${d}/overlay </dev/null ||
       die "/${d}/overlay wipe"
     reboot=true
@@ -309,9 +333,10 @@
 if ${reboot}; then
   echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
   adb_reboot &&
-    adb_wait 2m &&
-    adb_root ||
-    die "reboot after wipe"
+    adb_wait 2m ||
+    die "lost device after reboot after wipe"
+  adb_root ||
+    die "lost device after elevation to root after wipe"
 fi
 D=`adb_sh df -k </dev/null` &&
   H=`echo "${D}" | head -1` &&
@@ -320,91 +345,146 @@
   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 data |
-                cut -s -d' ' -f1`
+overlayfs_needed=true
+D=`adb_sh cat /proc/mounts </dev/null |
+   skip_administrative_mounts data |
+   cut -s -d' ' -f1`
+D=`adb_sh df -k ${D} </dev/null`
+echo "${D}"
+if [ X"${D}" = X"${D##* 100[%] }" ]; then
+  overlayfs_needed=false
+elif ! ${overlayfs_supported}; then
+  die "need overlayfs, but do not have it"
+fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} disable verity" >&2
 
 T=`adb_date`
-D=`adb disable-verity 2>&1`
+H=`adb disable-verity 2>&1`
 err=${?}
-if [ ${err} != 0 -o X"${D}" != X"${D##*setup failed}" ]; then
-  echo "${D%?Now reboot your device for settings to take effect}"
-  die -t ${T} "setup for overlay"
-fi
+L=
+D="${H%?Now reboot your device for settings to take effect}"
 if [ X"${D}" != X"${D##*using overlayfs}" ]; then
   echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
 fi
-reboot=false
-if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
-  echo "${GREEN}[       OK ]${NORMAL} disabled verity" >&2
-  reboot=true
-else
-  echo "${ORANGE}[  WARNING ]${NORMAL} verity already disabled" >&2
+if [ ${err} != 0 ]; then
+  echo "${H}"
+  ( [ -n "${L}" ] && echo "${L}" && false ) ||
+  die -t "${T}" "disable-verity"
 fi
-D=`adb_sh df -k </dev/null` &&
-  H=`echo "${D}" | head -1` &&
-  D=`echo "${D}" | grep "^overlay " | true` &&
-  [ -n "${D}" ] &&
-  ( echo "${H}" && echo "${D}" && true ) &&
-  die -t ${T} "overlay takeover unexpected"
-L=
-if ${reboot}; then
+rebooted=false
+if [ X"${D}" != X"${H}" -a X"${D}" = X"${D##*using overlayfs}" ]; then
+  echo "${H}"
+  if [ X"${D}" != X"${D##*setup failed}" ]; then
+    echo "${ORANGE}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
+  fi
+  D=`adb_sh df -k </dev/null` &&
+    H=`echo "${D}" | head -1` &&
+    D=`echo "${D}" | grep "^overlay "` &&
+    [ -n "${D}" ] &&
+    ( echo "${H}" && echo "${D}" ) &&
+    die -t ${T} "overlay takeover unexpected at this phase"
+  echo "${GREEN}[     INFO ]${NORMAL} rebooting as requested" >&2
   L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
   adb_reboot &&
     adb_wait 2m ||
-    die "reboot after verity disabled failed"
-  T=
+    die "lost device after reboot requested"
+  adb_root ||
+    die "lost device after elevation to root"
+  rebooted=true
+  # re-disable verity to see the setup remarks expected
+  T=`adb_date`
+  H=`adb disable-verity 2>&1`
+  err=${?}
+  D="${H%?Now reboot your device for settings to take effect}"
+  if [ X"${D}" != X"${D##*using overlayfs}" ]; then
+    echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
+  fi
+  if [ ${err} != 0 ]; then
+    T=
+  fi
+fi
+if ${overlayfs_supported} && ${overlayfs_needed} && [ X"${D}" != X"${D##*setup failed}" ]; then
+  echo "${D}"
+  ( [ -n "${L}" ] && echo "${L}" && false ) ||
+  die -t "${T}" "setup for overlay"
+fi
+if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
+  echo "${D}"
+  D=`adb_sh df -k </dev/null` &&
+    H=`echo "${D}" | head -1` &&
+    D=`echo "${D}" | grep "^overlay " | true` &&
+    [ -n "${D}" ] &&
+    ( echo "${H}" && echo "${D}" ) &&
+    ( [ -n "${L}" ] && echo "${L}" && false ) ||
+    die -t "${T}" "overlay takeover unexpected"
+  [ -n "${L}" ] && echo "${L}"
+  die -t "${T}" "unexpected report of verity being disabled a second time"
+elif ${rebooted}; then
+  echo "${GREEN}[       OK ]${NORMAL} verity already disabled" >&2
+else
+  echo "${ORANGE}[  WARNING ]${NORMAL} verity already disabled" >&2
 fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} remount" >&2
 
-adb_root &&
-  adb remount ||
+adb remount ||
   ( [ -n "${L}" ] && echo "${L}" && false ) ||
   die -t "${T}" "adb remount failed"
 D=`adb_sh df -k </dev/null` &&
   H=`echo "${D}" | head -1` &&
   D=`echo "${D}" | grep "^overlay "` ||
-  ( [ -n "${L}" ] && echo "${L}" && false ) ||
-  die -t ${T} "overlay takeover failed"
-echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
-  echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover not complete" >&2
-scratch_partition=scratch
-if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
-  echo "${BLUE}[     INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
-fi
-M=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
-[ -n "${M}" ] &&
-  echo "${BLUE}[     INFO ]${NORMAL} scratch filesystem ${M}"
-uses_dynamic_scratch=true
-if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
-  uses_dynamic_scratch=false
-  scratch_partition="${M##*/dev/block/by-name/}"
-fi
-scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
-              while read device kblocks used available use mounted on; do
-                if [ "/mnt/scratch" = "\${mounted}" ]; then
-                  echo \${kblocks}
-                fi
-              done` &&
-  [ -n "${scratch_size}" ] ||
-  die "scratch size"
-echo "${BLUE}[     INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
-for d in ${OVERLAYFS_BACKING}; do
-  if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
-    echo "${BLUE}[     INFO ]${NORMAL} /${d}/overlay is setup" >&2
+  ( [ -n "${L}" ] && echo "${L}" && false )
+ret=${?}
+uses_dynamic_scratch=false
+scratch_partition=
+if ${overlayfs_needed}; then
+  if [ ${ret} != 0 ]; then
+    die -t ${T} "overlay takeover failed"
   fi
-done
-
-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 data) ||
-  die "remount overlayfs missed a spot (ro)"
+   echo "${ORANGE}[  WARNING ]${NORMAL} overlay takeover not complete" >&2
+  scratch_partition=scratch
+  if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
+    echo "${BLUE}[     INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
+  fi
+  M=`adb_sh cat /proc/mounts </dev/null |
+     sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
+  [ -n "${M}" ] &&
+    echo "${BLUE}[     INFO ]${NORMAL} scratch filesystem ${M}"
+  uses_dynamic_scratch=true
+  if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
+    uses_dynamic_scratch=false
+    scratch_partition="${M##*/dev/block/by-name/}"
+  fi
+  scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
+                while read device kblocks used available use mounted on; do
+                  if [ "/mnt/scratch" = "\${mounted}" ]; then
+                    echo \${kblocks}
+                  fi
+                done` &&
+    [ -n "${scratch_size}" ] ||
+    die "scratch size"
+  echo "${BLUE}[     INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
+  for d in ${OVERLAYFS_BACKING}; do
+    if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
+      echo "${BLUE}[     INFO ]${NORMAL} /${d}/overlay is setup" >&2
+    fi
+  done
+
+  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 data) ||
+    die "remount overlayfs missed a spot (ro)"
+else
+  if [ ${ret} = 0 ]; then
+    die -t ${T} "unexpected overlay takeover"
+  fi
+fi
 
 # Check something
 
@@ -426,17 +506,19 @@
   adb_wait 2m ||
   die "reboot after override content added failed"
 
-D=`adb_su df -k </dev/null` &&
-  H=`echo "${D}" | head -1` &&
-  D=`echo "${D}" | grep "^overlay "` ||
-  ( echo "${L}" && false ) ||
-  die -d "overlay takeover failed after reboot"
+if ${overlayfs_needed}; then
+  D=`adb_su df -k </dev/null` &&
+    H=`echo "${D}" | head -1` &&
+    D=`echo "${D}" | grep "^overlay "` ||
+    ( echo "${L}" && false ) ||
+    die -d "overlay takeover failed after reboot"
 
-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
+  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
+fi
 
 B="`adb_cat /system/hello`" ||
   die "re-read system hello after reboot"
@@ -452,63 +534,75 @@
 
 echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
 
-[ -n "${ANDROID_PRODUCT_OUT}" ] &&
-  adb reboot-fastboot &&
-  fastboot_wait 2m &&
-  fastboot flash vendor ||
-  ( fastboot reboot && false) ||
-  die "fastboot flash vendor"
-fastboot_getvar partition-type:${scratch_partition} raw ||
-  ( fastboot reboot && false) ||
-  die "fastboot can not see ${scratch_partition} parameters"
-if ${uses_dynamic_scratch}; then
-  # check ${scratch_partition} via fastboot
-  fastboot_getvar has-slot:${scratch_partition} no &&
-    fastboot_getvar is-logical:${scratch_partition} yes ||
-    ( fastboot reboot && false) ||
-    die "fastboot can not see ${scratch_partition} parameters"
+H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
+elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} vendor image missing, skipping"
+elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} wrong vendor image, skipping"
 else
-  fastboot_getvar is-logical:${scratch_partition} no ||
+  adb reboot-fastboot &&
+    fastboot_wait 2m &&
+    fastboot flash vendor ||
     ( fastboot reboot && false) ||
-    die "fastboot can not see ${scratch_partition} parameters"
+    die "fastboot flash vendor"
+  if [ -n "${scratch_paritition}" ]; then
+    fastboot_getvar partition-type:${scratch_partition} raw ||
+      ( fastboot reboot && false) ||
+      die "fastboot can not see ${scratch_partition} parameters"
+    if ${uses_dynamic_scratch}; then
+      # check ${scratch_partition} via fastboot
+      fastboot_getvar has-slot:${scratch_partition} no &&
+        fastboot_getvar is-logical:${scratch_partition} yes ||
+        ( fastboot reboot && false) ||
+        die "fastboot can not see ${scratch_partition} parameters"
+    else
+      fastboot_getvar is-logical:${scratch_partition} no ||
+        ( fastboot reboot && false) ||
+        die "fastboot can not see ${scratch_partition} parameters"
+    fi
+    if ! ${uses_dynamic_scratch}; then
+      fastboot reboot-bootloader ||
+        die "Reboot into fastboot"
+    fi
+    if ${uses_dynamic_scratch}; then
+      echo "${BLUE}[     INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
+      fastboot erase ${scratch_partition} &&
+        ( fastboot reboot || true) &&
+        die "fastboot can erase ${scratch_partition}"
+    fi
+    echo "${BLUE}[     INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
+    fastboot format ${scratch_partition} &&
+      ( fastboot reboot || true) &&
+      die "fastboot can format ${scratch_partition}"
+  fi
+  fastboot reboot ||
+    die "can not reboot out of fastboot"
+  echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+  adb_wait 2m ||
+    die "did not reboot after flash"
+  if ${overlayfs_needed}; then
+    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"
+  fi
+  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
 fi
-if ! ${uses_dynamic_scratch}; then
-  fastboot reboot-bootloader ||
-    die "Reboot into fastboot"
-fi
-if ${uses_dynamic_scratch}; then
-  echo "${BLUE}[     INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
-  fastboot erase ${scratch_partition} &&
-    ( fastboot reboot || true) &&
-    die "fastboot can erase ${scratch_partition}"
-fi
-echo "${BLUE}[     INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
-fastboot format ${scratch_partition} &&
-  ( fastboot reboot || true) &&
-  die "fastboot can format ${scratch_partition}"
-fastboot reboot ||
-  die "can not reboot out of fastboot"
-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
 
 echo "${GREEN}[ RUN      ]${NORMAL} remove test content (cleanup)" >&2
 
@@ -524,32 +618,35 @@
   die "re-read vendor hello after rm"
 check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
 
-echo "${GREEN}[ RUN      ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+if [ -n "${scratch_partition}" ]; then
 
-adb reboot-fastboot ||
-  die "Reboot into fastbootd"
-dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
-  fastboot_wait 2m ||
-  ( rm /tmp/adb-remount-test.img && false) ||
-  die "reboot into fastboot"
-fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img
-err=${?}
-rm /tmp/adb-remount-test.img
-fastboot reboot ||
-  die "can not reboot out of fastboot"
-[ 0 -eq ${err} ] ||
-  die "fastboot flash ${scratch_partition}"
-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}" ] &&
-  echo "${GREEN}[       OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
-  die -t ${T} "setup for overlayfs"
+  echo "${GREEN}[ RUN      ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+
+  adb reboot-fastboot ||
+    die "Reboot into fastbootd"
+  dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
+    fastboot_wait 2m ||
+    ( rm /tmp/adb-remount-test.img && false) ||
+    die "reboot into fastboot"
+  fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img
+  err=${?}
+  rm /tmp/adb-remount-test.img
+  fastboot reboot ||
+    die "can not reboot out of fastboot"
+  [ 0 -eq ${err} ] ||
+    die "fastboot flash ${scratch_partition}"
+  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}" ] &&
+    echo "${GREEN}[       OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
+    die -t ${T} "setup for overlayfs"
+fi
 
 echo "${GREEN}[  PASSED  ]${NORMAL} adb remount" >&2
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index f5b291e..c96c381 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -42,6 +42,7 @@
 #include "uevent_listener.h"
 #include "util.h"
 
+using android::base::Split;
 using android::base::Timer;
 using android::fs_mgr::AvbHandle;
 using android::fs_mgr::AvbHashtreeResult;
@@ -56,7 +57,7 @@
 // ------------------
 class FirstStageMount {
   public:
-    FirstStageMount();
+    FirstStageMount(Fstab fstab);
     virtual ~FirstStageMount() = default;
 
     // The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
@@ -94,7 +95,7 @@
 
 class FirstStageMountVBootV1 : public FirstStageMount {
   public:
-    FirstStageMountVBootV1() = default;
+    FirstStageMountVBootV1(Fstab fstab) : FirstStageMount(std::move(fstab)) {}
     ~FirstStageMountVBootV1() override = default;
 
   protected:
@@ -106,7 +107,7 @@
   public:
     friend void SetInitAvbVersionInRecovery();
 
-    FirstStageMountVBootV2();
+    FirstStageMountVBootV2(Fstab fstab);
     ~FirstStageMountVBootV2() override = default;
 
   protected:
@@ -114,13 +115,17 @@
     bool SetUpDmVerity(FstabEntry* fstab_entry) override;
     bool InitAvbHandle();
 
-    std::string device_tree_vbmeta_parts_;
+    std::vector<std::string> vbmeta_partitions_;
     AvbUniquePtr avb_handle_;
 };
 
 // Static Functions
 // ----------------
-static inline bool IsDtVbmetaCompatible() {
+static inline bool IsDtVbmetaCompatible(const Fstab& fstab) {
+    if (std::any_of(fstab.begin(), fstab.end(),
+                    [](const auto& entry) { return entry.fs_mgr_flags.avb; })) {
+        return true;
+    }
     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
 }
 
@@ -128,21 +133,26 @@
     return access("/system/bin/recovery", F_OK) == 0;
 }
 
-// Class Definitions
-// -----------------
-FirstStageMount::FirstStageMount() : need_dm_verity_(false), uevent_listener_(16 * 1024 * 1024) {
-    if (!ReadFstabFromDt(&fstab_)) {
-        if (ReadDefaultFstab(&fstab_)) {
-            fstab_.erase(std::remove_if(fstab_.begin(), fstab_.end(),
-                                        [](const auto& entry) {
-                                            return !entry.fs_mgr_flags.first_stage_mount;
-                                        }),
-                         fstab_.end());
+static Fstab ReadFirstStageFstab() {
+    Fstab fstab;
+    if (!ReadFstabFromDt(&fstab)) {
+        if (ReadDefaultFstab(&fstab)) {
+            fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
+                                       [](const auto& entry) {
+                                           return !entry.fs_mgr_flags.first_stage_mount;
+                                       }),
+                        fstab.end());
         } else {
             LOG(INFO) << "Failed to fstab for first stage mount";
         }
     }
+    return fstab;
+}
 
+// Class Definitions
+// -----------------
+FirstStageMount::FirstStageMount(Fstab fstab)
+    : need_dm_verity_(false), fstab_(std::move(fstab)), uevent_listener_(16 * 1024 * 1024) {
     auto boot_devices = fs_mgr_get_boot_devices();
     device_handler_ = std::make_unique<DeviceHandler>(
             std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
@@ -152,10 +162,11 @@
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
-    if (IsDtVbmetaCompatible()) {
-        return std::make_unique<FirstStageMountVBootV2>();
+    auto fstab = ReadFirstStageFstab();
+    if (IsDtVbmetaCompatible(fstab)) {
+        return std::make_unique<FirstStageMountVBootV2>(std::move(fstab));
     } else {
-        return std::make_unique<FirstStageMountVBootV1>();
+        return std::make_unique<FirstStageMountVBootV1>(std::move(fstab));
     }
 }
 
@@ -492,22 +503,27 @@
     return true;  // Returns true to mount the partition.
 }
 
-// FirstStageMountVBootV2 constructor.
-// Gets the vbmeta partitions from device tree.
-// /{
-//     firmware {
-//         android {
-//             vbmeta {
-//                 compatible = "android,vbmeta";
-//                 parts = "vbmeta,boot,system,vendor"
-//             };
-//         };
-//     };
-//  }
-FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
-    if (!read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts_)) {
-        PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
-        return;
+// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab
+// for any further vbmeta partitions.
+FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
+    : FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
+    std::string device_tree_vbmeta_parts;
+    read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);
+
+    for (auto&& partition : Split(device_tree_vbmeta_parts, ",")) {
+        if (!partition.empty()) {
+            vbmeta_partitions_.emplace_back(std::move(partition));
+        }
+    }
+
+    for (const auto& entry : fstab_) {
+        if (!entry.vbmeta_partition.empty()) {
+            vbmeta_partitions_.emplace_back(entry.vbmeta_partition);
+        }
+    }
+
+    if (vbmeta_partitions_.empty()) {
+        LOG(ERROR) << "Failed to read vbmeta partitions.";
     }
 }
 
@@ -529,18 +545,15 @@
         }
     }
 
-    // libavb verifies AVB metadata on all verified partitions at once.
-    // e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
-    // for libavb to verify metadata, even if there is only /vendor in the
-    // above mount_fstab_recs_.
+    // Any partitions needed for verifying the partitions used in first stage mount, e.g. vbmeta
+    // must be provided as vbmeta_partitions.
     if (need_dm_verity_) {
-        if (device_tree_vbmeta_parts_.empty()) {
-            LOG(ERROR) << "Missing vbmeta parts in device tree";
+        if (vbmeta_partitions_.empty()) {
+            LOG(ERROR) << "Missing vbmeta partitions";
             return false;
         }
-        std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
         std::string ab_suffix = fs_mgr_get_slot_suffix();
-        for (const auto& partition : partitions) {
+        for (const auto& partition : vbmeta_partitions_) {
             std::string partition_name = partition + ab_suffix;
             if (logical_partitions.count(partition_name)) {
                 continue;
@@ -613,7 +626,9 @@
         return;
     }
 
-    if (!IsDtVbmetaCompatible()) {
+    auto fstab = ReadFirstStageFstab();
+
+    if (!IsDtVbmetaCompatible(fstab)) {
         LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
         return;
     }
@@ -623,7 +638,7 @@
     // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
     // Open() function returns a valid handle.
     // We don't need to mount partitions here in recovery mode.
-    FirstStageMountVBootV2 avb_first_mount;
+    FirstStageMountVBootV2 avb_first_mount(std::move(fstab));
     if (!avb_first_mount.InitDevices()) {
         LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
         return;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index db59569..1490fbc 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -84,7 +84,7 @@
     { 00750, AID_ROOT,         AID_SHELL,        0, "sbin" },
     { 00777, AID_ROOT,         AID_ROOT,         0, "sdcard" },
     { 00751, AID_ROOT,         AID_SDCARD_R,     0, "storage" },
-    { 00751, AID_ROOT,         AID_SHELL,        0, "system/bin" },
+    { 00755, AID_ROOT,         AID_SHELL,        0, "system/bin" },
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
index 56bd6c4..71c04a6 100644
--- a/libmetricslogger/include/metricslogger/metrics_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -116,7 +116,7 @@
     FIELD_BATTERY_RESISTANCE_UOHMS = 1448,
     FIELD_BATTERY_CURRENT_UA = 1449,
     FIELD_HARDWARE_LOCATION = 1450,
-    ACTION_BATTERY_CAUSED_SHUTDOWN = 1441,
+    ACTION_BATTERY_CAUSED_SHUTDOWN = 1451,
 };
 
 enum {