Merge changes I7a2dd830,I6ce43725,I5fc2f370,Ibc2e14bd,Idf213800, ...

* changes:
  fs_mgr_remount: support legacy devices (marlin)
  fs_mgr: remount: add -R argument
  fs_mgr: remount: add -T fstab argument
  fs_mgr: remount: log to stderr and logd
  fs_mgr: add remount command
  fs_mgr: overlayfs: test: add inRecovery check
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 974e13e..4ee9624 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -111,3 +111,35 @@
         "libgsi_headers",
     ],
 }
+
+cc_binary {
+    name: "remount",
+    defaults: ["fs_mgr_defaults"],
+    static_libs: [
+        "libavb_user",
+    ],
+    shared_libs: [
+        "libbootloader_message",
+        "libbase",
+        "libcrypto",
+        "libfec",
+        "libfs_mgr",
+    ],
+    header_libs: [
+        "libcutils_headers",
+    ],
+    srcs: [
+        "fs_mgr_remount.cpp",
+    ],
+    cppflags: [
+        "-DALLOW_ADBD_DISABLE_VERITY=0",
+    ],
+    product_variables: {
+        debuggable: {
+            cppflags: [
+                "-UALLOW_ADBD_DISABLE_VERITY",
+                "-DALLOW_ADBD_DISABLE_VERITY=1",
+            ],
+        },
+    },
+}
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
new file mode 100644
index 0000000..c0e0ccd
--- /dev/null
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libavb_user/libavb_user.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <bootloader_message/bootloader_message.h>
+#include <cutils/android_reboot.h>
+#include <fec/io.h>
+#include <fs_mgr_overlayfs.h>
+#include <fs_mgr_priv.h>
+#include <fstab/fstab.h>
+
+namespace {
+
+[[noreturn]] void usage(int exit_status) {
+    LOG(INFO) << getprogname()
+              << " [-h] [-R] [-T fstab_file]\n"
+                 "\t-h --help\tthis help\n"
+                 "\t-R --reboot\tdisable verity & reboot to facilitate remount\n"
+                 "\t-T --fstab\tcustom fstab file location\n"
+                 "\n"
+                 "Remount all partitions read-write.\n"
+                 "-R notwithstanding, verity must be disabled.";
+
+    ::exit(exit_status);
+}
+
+bool remountable_partition(const android::fs_mgr::FstabEntry& entry) {
+    if (entry.fs_mgr_flags.vold_managed) return false;
+    if (entry.fs_mgr_flags.recovery_only) return false;
+    if (entry.fs_mgr_flags.slot_select_other) return false;
+    if (!(entry.flags & MS_RDONLY)) return false;
+    if (entry.fs_type == "vfat") return false;
+    return true;
+}
+
+const std::string system_mount_point(const android::fs_mgr::FstabEntry& entry) {
+    if (entry.mount_point == "/") return "/system";
+    return entry.mount_point;
+}
+
+const android::fs_mgr::FstabEntry* is_wrapped(const android::fs_mgr::Fstab& overlayfs_candidates,
+                                              const android::fs_mgr::FstabEntry& entry) {
+    auto mount_point = system_mount_point(entry);
+    auto it = std::find_if(overlayfs_candidates.begin(), overlayfs_candidates.end(),
+                           [&mount_point](const auto& entry) {
+                               return android::base::StartsWith(mount_point,
+                                                                system_mount_point(entry) + "/");
+                           });
+    if (it == overlayfs_candidates.end()) return nullptr;
+    return &(*it);
+}
+
+void try_unmount_bionic(android::fs_mgr::Fstab* mounts) {
+    static constexpr const char* kBionic = "/bionic";
+
+    auto entry = GetEntryForMountPoint(mounts, kBionic);
+    if (!entry) return;
+
+    struct statfs buf;
+    if (::statfs(kBionic, &buf) == -1) {
+        PLOG(ERROR) << "statfs of " << kBionic;
+        return;
+    }
+    if (buf.f_flags & MS_RDONLY) {
+        // /bionic is on a read-only partition; can happen for
+        // non-system-as-root-devices. Don' try to unmount.
+        return;
+    }
+    fs_mgr_set_blk_ro(entry->blk_device, false);
+    if (::mount(entry->blk_device.c_str(), entry->mount_point.c_str(), entry->fs_type.c_str(),
+                MS_REMOUNT, nullptr) == -1) {
+        PLOG(ERROR) << "remount of " << kBionic;
+    }
+}
+
+void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+              const char* file, unsigned int line, const char* message) {
+    static const char log_characters[] = "VD\0WEFF";
+    if (severity < sizeof(log_characters)) {
+        auto severity_char = log_characters[severity];
+        if (severity_char) fprintf(stderr, "%c ", severity_char);
+    }
+    fprintf(stderr, "%s\n", message);
+
+    static auto logd = android::base::LogdLogger();
+    logd(id, severity, tag, file, line, message);
+}
+
+[[noreturn]] void reboot(bool dedupe) {
+    if (dedupe) {
+        LOG(INFO) << "The device will now reboot to recovery and attempt un-deduplication.";
+    } else {
+        LOG(INFO) << "Successfully disabled verity\nrebooting device";
+    }
+    ::sync();
+    android::base::SetProperty(ANDROID_RB_PROPERTY, dedupe ? "reboot,recovery" : "reboot,remount");
+    ::sleep(60);
+    ::exit(0);  // SUCCESS
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+    android::base::InitLogging(argv, MyLogger);
+
+    enum {
+        SUCCESS,
+        NOT_USERDEBUG,
+        BADARG,
+        NOT_ROOT,
+        NO_FSTAB,
+        VERITY_PARTITION,
+        BAD_OVERLAY,
+        NO_MOUNTS,
+        REMOUNT_FAILED,
+    } retval = SUCCESS;
+
+    // If somehow this executable is delivered on a "user" build, it can
+    // not function, so providing a clear message to the caller rather than
+    // letting if fall through and provide a lot of confusing failure messages.
+    if (!ALLOW_ADBD_DISABLE_VERITY || (android::base::GetProperty("ro.debuggable", "0") != "1")) {
+        LOG(ERROR) << "only functions on userdebug or eng builds";
+        return NOT_USERDEBUG;
+    }
+
+    const char* fstab_file = nullptr;
+    auto can_reboot = false;
+
+    struct option longopts[] = {
+            {"fstab", required_argument, nullptr, 'T'},
+            {"help", no_argument, nullptr, 'h'},
+            {"reboot", no_argument, nullptr, 'R'},
+            {0, 0, nullptr, 0},
+    };
+    for (int opt; (opt = ::getopt_long(argc, argv, "hRT:", longopts, nullptr)) != -1;) {
+        switch (opt) {
+            case 'R':
+                can_reboot = true;
+                break;
+            case 'T':
+                if (fstab_file) {
+                    LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
+                    usage(BADARG);
+                }
+                fstab_file = optarg;
+                break;
+            default:
+                LOG(ERROR) << "Bad Argument -" << char(opt);
+                usage(BADARG);
+                break;
+            case 'h':
+                usage(SUCCESS);
+                break;
+        }
+    }
+
+    if (argc > optind) {
+        LOG(ERROR) << "Bad Argument " << argv[optind];
+        usage(BADARG);
+    }
+
+    // Make sure we are root.
+    if (::getuid() != 0) {
+        LOG(ERROR) << "must be run as root";
+        return NOT_ROOT;
+    }
+
+    // Read the selected fstab.
+    android::fs_mgr::Fstab fstab;
+    auto fstab_read = false;
+    if (fstab_file) {
+        fstab_read = android::fs_mgr::ReadFstabFromFile(fstab_file, &fstab);
+    } else {
+        fstab_read = android::fs_mgr::ReadDefaultFstab(&fstab);
+    }
+    if (!fstab_read || fstab.empty()) {
+        PLOG(ERROR) << "Failed to read fstab";
+        return NO_FSTAB;
+    }
+
+    // Generate the list of supported overlayfs mount points.
+    auto overlayfs_candidates = fs_mgr_overlayfs_candidate_list(fstab);
+
+    // Generate the all remountable partitions sub-list
+    android::fs_mgr::Fstab partitions;
+    for (auto const& entry : fstab) {
+        if (!remountable_partition(entry)) continue;
+        if (overlayfs_candidates.empty() ||
+            GetEntryForMountPoint(&overlayfs_candidates, entry.mount_point) ||
+            (is_wrapped(overlayfs_candidates, entry) == nullptr)) {
+            partitions.emplace_back(entry);
+        }
+    }
+
+    // Check verity and optionally setup overlayfs backing.
+    auto reboot_later = false;
+    for (auto it = partitions.begin(); it != partitions.end();) {
+        auto& entry = *it;
+        auto& mount_point = entry.mount_point;
+        if (fs_mgr_is_verity_enabled(entry)) {
+            LOG(WARNING) << "Verity enabled on " << mount_point;
+            if (can_reboot &&
+                (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked")) {
+                if (AvbOps* ops = avb_ops_user_new()) {
+                    auto ret = avb_user_verity_set(
+                            ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(),
+                            false);
+                    avb_ops_user_free(ops);
+                    if (ret) {
+                        if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
+                            retval = VERITY_PARTITION;
+                            // w/o overlayfs available, also check for dedupe
+                            reboot_later = true;
+                            ++it;
+                            continue;
+                        }
+                        reboot(false);
+                    } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) {
+                        fec::io fh(entry.blk_device.c_str(), O_RDWR);
+                        if (fh && fh.set_verity_status(false)) reboot_later = true;
+                    }
+                }
+            }
+            LOG(ERROR) << "Skipping " << mount_point;
+            retval = VERITY_PARTITION;
+            it = partitions.erase(it);
+            continue;
+        }
+
+        auto change = false;
+        errno = 0;
+        if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change)) {
+            if (change) {
+                LOG(INFO) << "Using overlayfs for " << mount_point;
+            }
+        } else if (errno) {
+            PLOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
+            retval = BAD_OVERLAY;
+            it = partitions.erase(it);
+            continue;
+        }
+        ++it;
+    }
+
+    if (partitions.empty()) {
+        if (reboot_later) reboot(false);
+        LOG(WARNING) << "No partitions to remount";
+        return retval;
+    }
+
+    // Mount overlayfs.
+    if (!fs_mgr_overlayfs_mount_all(&partitions)) {
+        retval = BAD_OVERLAY;
+        PLOG(ERROR) << "Can not mount overlayfs for partitions";
+    }
+
+    // Get actual mounts _after_ overlayfs has been added.
+    android::fs_mgr::Fstab mounts;
+    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts) || mounts.empty()) {
+        PLOG(ERROR) << "Failed to read /proc/mounts";
+        retval = NO_MOUNTS;
+    }
+
+    // Remount selected partitions.
+    for (auto& entry : partitions) {
+        // unlock the r/o key for the mount point device
+        if (entry.fs_mgr_flags.logical) {
+            fs_mgr_update_logical_partition(&entry);
+        }
+        auto blk_device = entry.blk_device;
+        auto mount_point = entry.mount_point;
+
+        for (auto it = mounts.rbegin(); it != mounts.rend(); ++it) {
+            auto& rentry = *it;
+            if (mount_point == rentry.mount_point) {
+                blk_device = rentry.blk_device;
+                break;
+            }
+            if ((mount_point == "/") && (rentry.mount_point == "/system")) {
+                if (blk_device != "/dev/root") blk_device = rentry.blk_device;
+                mount_point = "/system";
+                break;
+            }
+        }
+        fs_mgr_set_blk_ro(blk_device, false);
+
+        // Now remount!
+        if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
+                    nullptr) == 0) {
+            continue;
+        }
+        if ((errno == EINVAL) && (mount_point != entry.mount_point)) {
+            mount_point = entry.mount_point;
+            if (::mount(blk_device.c_str(), mount_point.c_str(), entry.fs_type.c_str(), MS_REMOUNT,
+                        nullptr) == 0) {
+                continue;
+            }
+        }
+        PLOG(WARNING) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point;
+        // If errno = EROFS at this point, we are dealing with r/o
+        // filesystem types like squashfs, erofs or ext4 dedupe. We will
+        // consider such a device that does not have CONFIG_OVERLAY_FS
+        // in the kernel as a misconfigured; except for ext4 dedupe.
+        if ((errno == EROFS) && can_reboot) {
+            const std::vector<std::string> msg = {"--fsck_unshare_blocks"};
+            std::string err;
+            if (write_bootloader_message(msg, &err)) reboot(true);
+            LOG(ERROR) << "Failed to set bootloader message: " << err;
+            errno = EROFS;
+        }
+        retval = REMOUNT_FAILED;
+    }
+
+    if (reboot_later) reboot(false);
+
+    try_unmount_bionic(&mounts);
+
+    return retval;
+}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index fd53ed4..1ded954 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -70,19 +70,37 @@
 Returns: true if device is in adb mode" ]
 inAdb() {
   adb devices |
-    grep -v -e 'List of devices attached' -e '^$' |
+    grep -v -e 'List of devices attached' -e '^$' -e "[${SPACE}${TAB}]recovery\$" |
     if [ -n "${ANDROID_SERIAL}" ]; then
       grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
     else
       wc -l | grep '^1$' >/dev/null
     fi
 }
+[ "USAGE: inRecovery
+
+Returns: true if device is in recovery mode" ]
+inRecovery() {
+  local list="`adb devices |
+              grep -v -e 'List of devices attached' -e '^$'`"
+  if [ -n "${ANDROID_SERIAL}" ]; then
+    echo "${list}" |
+      grep "^${ANDROID_SERIAL}[${SPACE}${TAB}][${SPACE}${TAB}]*recovery\$" >/dev/null
+    return ${?}
+  fi
+  if echo "${list}" | wc -l | grep '^1$' >/dev/null; then
+    echo "${list}" |
+      grep "[${SPACE}${TAB}]recovery\$" >/dev/null
+    return ${?}
+  fi
+  false
+}
 
 [ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
 
 Returns: true if the command succeeded" ]
 adb_sh() {
-  args=
+  local args=
   for i in "${@}"; do
     [ -z "${args}" ] || args="${args} "
     if [ X"${i}" != X"${i#\'}" ]; then
@@ -143,10 +161,10 @@
 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=${?}
+    local OUTPUT="`adb_sh cat ${1} </dev/null 2>&1`"
+    local ret=${?}
     echo "${OUTPUT}" | tr -d '\r'
-    return ${retval}
+    return ${ret}
 }
 
 [ "USAGE: adb_reboot
@@ -165,7 +183,7 @@
     echo unknown
     return
   fi
-  duration="${1}"
+  local duration="${1}"
   if [ X"${duration}" != X"${duration%s}" ]; then
     duration=${duration%s}
   elif [ X"${duration}" != X"${duration%m}" ]; then
@@ -175,9 +193,9 @@
   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`
+  local seconds=`expr ${duration} % 60`
+  local minutes=`expr \( ${duration} / 60 \) % 60`
+  local hours=`expr ${duration} / 3600`
   if [ 0 -eq ${minutes} -a 0 -eq ${hours} ]; then
     if [ 1 -eq ${duration} ]; then
       echo 1 second
@@ -205,10 +223,10 @@
 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=${?}
+    timeout --preserve-status --signal=KILL ${1} adb wait-for-device 2>/dev/null
+    local ret=${?}
     echo -n "                                                                             ${CR}"
-    return ${retval}
+    return ${ret}
   else
     adb wait-for-device
   fi
@@ -216,12 +234,15 @@
 
 [ "USAGE: usb_status > stdout
 
-If adb_wait failed, check if device is in fastboot mode and report status
+If adb_wait failed, check if device is in adb, recovery or fastboot mode
+and report status string.
 
 Returns: \"(USB stack borken?)\", \"(In fastboot mode)\" or \"(in adb mode)\"" ]
 usb_status() {
   if inFastboot; then
     echo "(In fastboot mode)"
+  elif inRecovery; then
+    echo "(In recovery mode)"
   elif inAdb; then
     echo "(In adb mode)"
   else
@@ -238,15 +259,47 @@
   if [ -n "${1}" ]; then
     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=${?}
+    local ret=${?}
     echo -n "                                                                             ${CR}"
-    ( exit ${retval} )
+    ( exit ${ret} )
   else
     fastboot wait-for-device >/dev/null 2>/dev/null
   fi ||
     inFastboot
 }
 
+[ "USAGE: recovery_wait [timeout]
+
+Returns: waits until the device has returned for recovery or optional timeout" ]
+recovery_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-recovery 2>/dev/null
+    local ret=${?}
+    echo -n "                                                                             ${CR}"
+    return ${ret}
+  else
+    adb wait-for-recovery
+  fi
+}
+
+[ "any_wait [timeout]
+
+Returns: waits until a device has returned or optional timeout" ]
+any_wait() {
+  (
+    adb_wait ${1} &
+    adb_pid=${!}
+    fastboot_wait ${1} &
+    fastboot_pid=${!}
+    recovery_wait ${1} &
+    recovery_pid=${!}
+    wait -n
+    kill "${adb_pid}" "${fastboot_pid}" "${recovery_pid}"
+  ) >/dev/null 2>/dev/null
+  inFastboot || inAdb || inRecovery
+}
+
 [ "USAGE: adb_root
 
 NB: This can be flakey on devices due to USB state
@@ -277,11 +330,11 @@
 
 Returns: true if var output matches expected" ]
 fastboot_getvar() {
-  O=`fastboot getvar ${1} 2>&1`
-  err=${?}
+  local O=`fastboot getvar ${1} 2>&1`
+  local ret=${?}
   O="${O#< waiting for * >?}"
   O="${O%%?Finished. Total time: *}"
-  if [ 0 -ne ${err} ]; then
+  if [ 0 -ne ${ret} ]; then
     echo ${O} >&2
     false
     return
@@ -325,7 +378,7 @@
     echo "${BLUE}[     INFO ]${NORMAL} end `date`"
     [ -n "${start_time}" ] || return
     end_time=`date +%s`
-    diff_time=`expr ${end_time} - ${start_time}`
+    local diff_time=`expr ${end_time} - ${start_time}`
     echo "${BLUE}[     INFO ]${NORMAL} duration `format_duration ${diff_time}`"
   fi >&2
 }
@@ -358,8 +411,8 @@
 
 Returns true if (regex) lval matches rval" ]
 EXPECT_EQ() {
-  lval="${1}"
-  rval="${2}"
+  local lval="${1}"
+  local 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%
@@ -404,10 +457,10 @@
 
 Exits if (regex) lval mismatches rval" ]
 check_eq() {
-  left="${1}"
-  right="${2}"
+  local lval="${1}"
+  local rval="${2}"
   shift 2
-  EXPECT_EQ "${left}" "${right}" ||
+  EXPECT_EQ "${lval}" "${rval}" ||
     die "${@}"
 }
 
@@ -498,15 +551,16 @@
 fi
 
 inFastboot && die "device in fastboot mode"
+inRecovery && die "device in recovery mode"
 if ! inAdb; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode"
+  echo "${ORANGE}[  WARNING ]${NORMAL} device not in adb mode" >&2
   adb_wait 2m
 fi
 inAdb || die "specified device not in adb mode"
 isDebuggable || die "device not a debug build"
 enforcing=true
 if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then
-  echo "${ORANGE}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode"
+  echo "${ORANGE}[  WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2
   enforcing=false
 fi
 
@@ -563,6 +617,19 @@
       adb_reboot &&
       adb_wait 2m
   }
+
+  echo "${GREEN}[ RUN      ]${NORMAL} Testing adb shell su root remount -R command" >&2
+
+  adb_su remount -R </dev/null || true
+  sleep 2
+  adb_wait 2m ||
+    die "waiting for device after remount -R `usb_status`"
+  if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
+       "2" = "`get_property partition.system.verified`" ]; then
+    die "remount -R command failed"
+  fi
+
+  echo "${GREEN}[       OK ]${NORMAL} adb shell su root remount -R command" >&2
 fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} Testing kernel support for overlayfs" >&2
@@ -577,7 +644,7 @@
   ) ||
   overlayfs_supported=false
 if ${overlayfs_supported}; then
-  adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
+  adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null 2>/dev/null &&
     echo "${GREEN}[       OK ]${NORMAL} overlay module supports override_creds" >&2 ||
     case `adb_sh uname -r </dev/null` in
       4.[456789].* | 4.[1-9][0-9]* | [56789].*)
@@ -857,21 +924,20 @@
     echo "${GREEN}[       OK ]${NORMAL} overlay takeover in first stage init" >&2
 fi
 
-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.
 if ${enforcing}; then
-  adb_unroot
-  B="`adb_cat /vendor/hello`" &&
-    die "re-read /vendor/hello after reboot w/o root"
+  adb_unroot ||
+    die "device not in unroot'd state"
+  B="`adb_cat /vendor/hello 2>&1`"
   check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
   echo "${GREEN}[       OK ]${NORMAL} /vendor content correct MAC after reboot" >&2
 fi
-adb_root &&
-  B="`adb_cat /vendor/hello`" ||
-  die "re-read /vendor/hello after reboot"
+B="`adb_cat /system/hello`"
+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.
+adb_root ||
+  die "adb root"
+B="`adb_cat /vendor/hello`"
 check_eq "${A}" "${B}" vendor after reboot
 echo "${GREEN}[       OK ]${NORMAL} /vendor content remains after reboot" >&2
 
@@ -901,8 +967,9 @@
 else
   adb reboot-fastboot ||
     die "fastbootd not supported (wrong adb in path?)"
-  fastboot_wait 2m ||
-    die "reboot into fastboot to flash vendor `usb_status`"
+  any_wait 2m &&
+    inFastboot ||
+    die "reboot into fastboot to flash vendor `usb_status` (bad bootloader?)"
   fastboot flash vendor ||
     ( fastboot reboot && false) ||
     die "fastboot flash vendor"
@@ -956,12 +1023,11 @@
       if ${is_userspace_fastboot}; then
         die  "overlay supposed to be minus /vendor takeover after flash vendor"
       else
-        echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
-        ( die  "overlay supposed to be minus /vendor takeover after flash vendor" )
+        echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+        echo "${ORANGE}[  WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2
       fi
   fi
-  B="`adb_cat /system/hello`" ||
-    die "re-read /system/hello after flash vendor"
+  B="`adb_cat /system/hello`"
   check_eq "${A}" "${B}" system after flash vendor
   adb_root ||
     die "adb root"
@@ -969,13 +1035,21 @@
     if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
       die "re-read /vendor/hello after flash vendor"
     else
-      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
-      ( die "re-read /vendor/hello after flash vendor" )
+      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+      echo "${ORANGE}[  WARNING ]${NORMAL} re-read /vendor/hello after flash vendor" >&2
     fi
   if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
-    check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+    check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
+             vendor content after flash vendor
   else
-    ( check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor )
+    (
+      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+      restore() {
+        true
+      }
+      check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
+               vendor content after flash vendor
+    )
   fi
 fi
 
@@ -1003,12 +1077,10 @@
   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"
-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
+B="`adb_cat /system/hello`"
+check_eq "cat: /system/hello: No such file or directory" "${B}" after rm
+B="`adb_cat /vendor/hello`"
+check_eq "cat: /vendor/hello: No such file or directory" "${B}" after rm
 
 if [ -n "${scratch_partition}" ]; then
 
@@ -1081,9 +1153,56 @@
   die "/vendor is not read-write"
 echo "${GREEN}[       OK ]${NORMAL} mount -o rw,remount command works" >&2
 
+# Prerequisite is a prepped device from above.
+adb_reboot &&
+  adb_wait 2m ||
+  die "lost device after reboot to ro state (USB stack broken?)"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
+  die "/vendor is not read-only"
+adb_su remount </dev/null ||
+  die "remount command"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
+  die "/vendor is not read-write"
+echo "${GREEN}[       OK ]${NORMAL} remount command works from setup" >&2
+
+# Prerequisite is an overlayfs deconstructed device but with verity disabled.
+# This also saves a lot of 'noise' from the command doing a mkfs on backing
+# storage and all the related tuning and adjustment.
+for d in ${OVERLAYFS_BACKING}; do
+  adb_su rm -rf /${d}/overlay </dev/null ||
+    die "/${d}/overlay wipe"
+done
+adb_reboot &&
+  adb_wait 2m ||
+  die "lost device after reboot after wipe (USB stack broken?)"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
+  die "/vendor is not read-only"
+adb_su remount </dev/null ||
+  die "remount command"
+adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
+  die "/vendor is not read-write"
+echo "${GREEN}[       OK ]${NORMAL} remount command works from scratch" >&2
+
 restore
 err=${?}
 
+if [ ${err} = 0 ] && ${overlayfs_supported}; then
+  echo "${GREEN}[ RUN      ]${NORMAL} test 'adb remount -R'" >&2
+  adb_root &&
+    adb remount -R &&
+    adb_wait 2m ||
+    die "adb remount -R"
+  if [ "orange" != "`get_property ro.boot.verifiedbootstate`" -o \
+       "2" = "`get_property partition.system.verified`" ]; then
+    die "remount -R command failed to disable verity"
+  fi
+
+  echo "${GREEN}[       OK ]${NORMAL} 'adb remount -R' command" >&2
+
+  restore
+  err=${?}
+fi
+
 restore() {
   true
 }