Merge "Add support for caching small reads."
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e066bff..0978ec1 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -162,9 +162,17 @@
         // clang-format on
 };
 
-static std::string find_item_given_name(const std::string& img_name) {
+static char* get_android_product_out() {
     char* dir = getenv("ANDROID_PRODUCT_OUT");
     if (dir == nullptr || dir[0] == '\0') {
+        return nullptr;
+    }
+    return dir;
+}
+
+static std::string find_item_given_name(const std::string& img_name) {
+    char* dir = get_android_product_out();
+    if (!dir) {
         die("ANDROID_PRODUCT_OUT not set");
     }
     return std::string(dir) + "/" + img_name;
@@ -1466,15 +1474,13 @@
             fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
             return;
         }
-        fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
-                partition_type.c_str());
-        return;
+        die("Formatting is not supported for file system with type '%s'.",
+            partition_type.c_str());
     }
 
     int64_t size;
     if (!android::base::ParseInt(partition_size, &size)) {
-        fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
-        return;
+        die("Couldn't parse partition size '%s'.", partition_size.c_str());
     }
 
     unsigned eraseBlkSize, logicalBlkSize;
@@ -1484,17 +1490,14 @@
     if (fs_generator_generate(gen, output.path, size, initial_dir,
             eraseBlkSize, logicalBlkSize)) {
         die("Cannot generate image for %s", partition.c_str());
-        return;
     }
 
     fd.reset(open(output.path, O_RDONLY));
     if (fd == -1) {
-        fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
-        return;
+        die("Cannot open generated image: %s", strerror(errno));
     }
     if (!load_buf_fd(fd.release(), &buf)) {
-        fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
-        return;
+        die("Cannot read image: %s", strerror(errno));
     }
     flash_buf(partition, &buf);
     return;
@@ -1505,9 +1508,15 @@
         if (errMsg) fprintf(stderr, "%s", errMsg);
     }
     fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+    if (!skip_if_not_supported) {
+        die("Command failed");
+    }
 }
 
 static bool should_flash_in_userspace(const std::string& partition_name) {
+    if (!get_android_product_out()) {
+        return false;
+    }
     auto path = find_item_given_name("super_empty.img");
     if (path.empty()) {
         return false;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8e57e1e..6310238 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1603,9 +1603,6 @@
         } else if (slot == -1) {
             suffix = fs_mgr_get_slot_suffix();
         }
-        if (suffix.empty()) {
-            LFATAL << "Super partition name can only be overridden on A/B devices.";
-        }
         return super_partition + suffix;
     }
     return LP_METADATA_DEFAULT_PARTITION_NAME;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a1de005..23e9c51 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -432,7 +432,7 @@
         if (change) *change = true;
         if (!DestroyLogicalPartition(partition_name, 0s)) return false;
     } else {
-        PERROR << "delete partition " << overlay;
+        LERROR << "delete partition " << overlay;
         return false;
     }
     errno = save_errno;
@@ -647,49 +647,65 @@
     if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
     auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
     auto scratch_device = fs_mgr_overlayfs_scratch_device();
-    auto partition_exists = fs_mgr_rw_access(scratch_device);
+    auto partition_create = !fs_mgr_rw_access(scratch_device);
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return false;
+    if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) {
+        LERROR << "open " << super_device << " metadata";
+        return false;
+    }
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    auto partition = builder->FindPartition(partition_name);
+    auto partition_exists = partition != nullptr;
+    auto changed = false;
     if (!partition_exists) {
-        auto slot_number = fs_mgr_overlayfs_slot_number();
-        auto super_device = fs_mgr_overlayfs_super_device(slot_number);
-        if (!fs_mgr_rw_access(super_device)) return false;
-        if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
-        auto builder = MetadataBuilder::New(super_device, slot_number);
-        if (!builder) {
-            PERROR << "open " << super_device << " metadata";
+        partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+        if (!partition) {
+            LERROR << "create " << partition_name;
             return false;
         }
-        const auto partition_name = android::base::Basename(kScratchMountPoint);
-        partition_exists = builder->FindPartition(partition_name) != nullptr;
-        if (!partition_exists) {
-            auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
-            if (!partition) {
-                PERROR << "create " << partition_name;
-                return false;
+        changed = true;
+    }
+    // Take half of free space, minimum 512MB or free space - 256KB margin.
+    static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
+    static constexpr auto kMarginSize = uint64_t(256 * 1024);
+    if (partition->size() < kMinimumSize) {
+        auto partition_size =
+                builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+        if ((partition_size > kMinimumSize) || !partition->size()) {
+            partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
+                                      partition_size / 2);
+            if (partition_size > partition->size()) {
+                if (!builder->ResizePartition(partition, partition_size)) {
+                    LERROR << "resize " << partition_name;
+                    return false;
+                }
+                if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+                changed = true;
+                partition_exists = false;
             }
-            auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
-            // 512MB or half the remaining available space, whichever is greater.
-            partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
-            if (!builder->ResizePartition(partition, partition_size)) {
-                PERROR << "resize " << partition_name;
-                return false;
-            }
-
-            auto metadata = builder->Export();
-            if (!metadata) {
-                LERROR << "generate new metadata " << partition_name;
-                return false;
-            }
-            if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
-                LERROR << "update " << partition_name;
-                return false;
-            }
-
-            if (change) *change = true;
+        }
+    }
+    // land the update back on to the partition
+    if (changed) {
+        auto metadata = builder->Export();
+        if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+            LERROR << "add partition " << partition_name;
+            return false;
         }
 
+        if (change) *change = true;
+    }
+
+    if (changed || partition_create) {
         if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
                                     &scratch_device))
             return false;
+
+        if (change) *change = true;
     }
 
     if (partition_exists) {
@@ -709,6 +725,7 @@
     } else if (mnt_type == "ext4") {
         command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
     } else {
+        errno = ESRCH;
         LERROR << mnt_type << " has no mkfs cookbook";
         return false;
     }
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 7a00194..d9e017c 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -63,6 +63,7 @@
 
 Returns: the logcat output" ]
 adb_logcat() {
+  echo "${RED}[     INFO ]${NORMAL} logcat ${@}" >&2 &&
   adb logcat "${@}" </dev/null |
     grep -v 'logd    : logdr: UID=' |
     sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
@@ -106,12 +107,13 @@
 
 Returns: true if the reboot command succeeded" ]
 adb_reboot() {
-  adb reboot remount-test
+  adb reboot remount-test &&
+  sleep 2
 }
 
 [ "USAGE: adb_wait [timeout]
 
-Returns: waits until the device has returned or the optional timeout" ]
+Returns: waits until the device has returned for adb or optional timeout" ]
 adb_wait() {
   if [ -n "${1}" ]; then
     timeout --preserve-status --signal=KILL ${1} adb wait-for-device
@@ -120,14 +122,49 @@
   fi
 }
 
+[ "USAGE: fastboot_wait [timeout]
+
+Returns: waits until the device has returned for fastboot or optional timeout" ]
+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
+  else
+    fastboot wait-for-device >/dev/null
+  fi >/dev/null 2>/dev/null ||
+    inFastboot
+}
+
 [ "USAGE: adb_root
 
 Returns: true if device in root state" ]
 adb_root() {
-  adb root >/dev/null </dev/null 2>/dev/null &&
-  sleep 1 &&
-  adb_wait &&
-  sleep 1
+  adb root >/dev/null </dev/null 2>/dev/null
+  sleep 2
+  adb_wait 2m &&
+    [ `adb_sh echo '${USER}'` = root ]
+}
+
+[ "USAGE: fastboot_getvar var expected
+
+Returns: true if var output matches expected" ]
+fastboot_getvar() {
+  O=`fastboot getvar ${1} 2>&1`
+  err=${?}
+  O="${O#< waiting for * >?}"
+  O="${O%%?Finished. Total time: *}"
+  if [ 0 -ne ${err} ]; then
+    echo ${O} >&2
+    false
+    return
+  fi
+  if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
+    echo "${2} != ${O}" >&2
+    false
+    return
+  fi
+  echo ${O} >&2
 }
 
 [ "USAGE: die [-t <epoch>] [message] >/dev/stderr
@@ -233,8 +270,7 @@
 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"
-adb_root &&
-  adb_wait ||
+adb_root ||
   die "initial setup"
 reboot=false
 OVERLAYFS_BACKING="cache mnt/scratch"
@@ -250,8 +286,7 @@
   echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
   adb_reboot &&
     adb_wait 2m &&
-    adb_root &&
-    adb_wait ||
+    adb_root ||
     die "reboot after wipe"
 fi
 D=`adb_sh df -k </dev/null` &&
@@ -288,7 +323,6 @@
 
 T=`adb_date`
 adb_root &&
-  adb_wait &&
   adb remount &&
   D=`adb_sh df -k </dev/null` ||
   die -t ${T} "can not collect filesystem data"
@@ -340,19 +374,31 @@
   die "re-read vendor hello after reboot w/o root"
 check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
 adb_root &&
-  adb_wait &&
   B="`adb_cat /vendor/hello`" ||
   die "re-read vendor hello after reboot"
 check_eq "${A}" "${B}" vendor after reboot
 
 adb reboot-fastboot &&
-  fastboot flash vendor &&
-  fastboot reboot ||
+  fastboot_wait 2m &&
+  fastboot flash vendor ||
   die "fastbootd flash vendor"
+# check scratch via fastboot
+fastboot_getvar partition-type:scratch raw &&
+  fastboot_getvar has-slot:scratch no &&
+  fastboot_getvar is-logical:scratch yes ||
+  die "fastboot can not see scratch parameters"
+echo "${ORANGE}[     INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
+fastboot erase scratch &&
+  die "fastbootd can erase scratch"
+echo "${ORANGE}[     INFO ]${NORMAL} expect fastboot format scratch to fail" >&2
+fastboot format scratch &&
+  die "fastbootd can format scratch"
+fastboot reboot ||
+  die "can not reboot out of fastbootd"
+echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
 adb_wait 2m ||
   die "did not reboot after flash"
 adb_root &&
-  adb_wait &&
   D=`adb_sh df -k </dev/null` &&
   H=`echo "${D}" | head -1` &&
   D=`echo "${D}" | grep "^overlay "` &&
@@ -365,8 +411,7 @@
 B="`adb_cat /system/hello`" ||
   die "re-read system hello after flash vendor"
 check_eq "${A}" "${B}" system after flash vendor
-adb_root &&
-  adb_wait ||
+adb_root ||
   die "adb root"
 B="`adb_cat /vendor/hello`" &&
   die "re-read vendor hello after flash vendor"
@@ -384,4 +429,27 @@
   die "re-read vendor hello after rm"
 check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
 
+adb reboot-fastboot &&
+  dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
+  fastboot_wait 2m ||
+  die "reboot into fastbootd"
+fastboot flash scratch adb-remount-test.img
+err=${?}
+rm adb-remount-test.img
+[ 0 -eq ${err} ] ||
+  die "fastbootd flash scratch"
+fastboot reboot ||
+  die "can not reboot out of fastbootd"
+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}" ] ||
+  die -t ${T} "setup for overlayfs"
+
 echo "${GREEN}[  PASSED  ]${NORMAL} adb remount" >&2
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43b2ebf..a3257f5 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -449,7 +449,9 @@
     // Includes the partition names of fstab records and verity_loc_device (if any).
     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
     for (auto fstab_rec : mount_fstab_recs_) {
-        required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        if (!fs_mgr_is_logical(fstab_rec)) {
+            required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        }
     }
 
     if (!verity_loc_device.empty()) {