remount: Refactor fs_mgr_overlayfs_scratch_device().

This splits fs_mgr_overlayfs_scratch_device into two new methods. The
first, GetScratchStrategy, returns an enum detailing exactly how the
device will find space for scratch:
 - via system_<other>,
 - via super_<other>, or
 - via a dynamic partition.

The second method, GetScratchDevice, uses the strategy to either return
the underlying block device, or look up a dynamic partition.

fs_mgr_overlayfs_scratch_device will be removed completely in a separate
patch.

Bug: 134949511
Test: adb remount and adb_remount_test.sh
Change-Id: Ic7e3815ada4adaf5fd7c19b84dc22249f3dcc881
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 05f3311..2337065 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -815,26 +815,72 @@
     return "auto";
 }
 
-std::string fs_mgr_overlayfs_scratch_device() {
-    if (!scratch_device_cache.empty()) return scratch_device_cache;
+enum class ScratchStrategy {
+    kNone,
+    // DAP device, use logical partitions.
+    kDynamicPartition,
+    // Retrofit DAP device, use super_<other>.
+    kSuperOther,
+    // Pre-DAP device, uses the other slot.
+    kSystemOther
+};
 
-    // Is this a multiple super device (retrofit)?
+static ScratchStrategy GetScratchStrategy(std::string* backing_device) {
     auto slot_number = fs_mgr_overlayfs_slot_number();
     auto super_device = fs_mgr_overlayfs_super_device(slot_number);
     auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
-    if (super_device == path) {
-        // Create from within single super device;
-        auto& dm = DeviceMapper::Instance();
-        const auto partition_name = android::base::Basename(kScratchMountPoint);
-        if (!dm.GetDmDevicePathByName(partition_name, &path)) {
-            // non-DAP A/B device?
-            if (fs_mgr_access(super_device)) return "";
-            auto other_slot = fs_mgr_get_other_slot_suffix();
-            if (other_slot.empty()) return "";
-            path = kPhysicalDevice + "system" + other_slot;
+    if (super_device != path) {
+        // Note: we do not check access() here, since in first-stage init we
+        // wouldn't have registed by-name symlinks for the device as it's
+        // normally not needed. The access checks elsewhere in this function
+        // are safe because system/super are always required.
+        *backing_device = path;
+        return ScratchStrategy::kSuperOther;
+    }
+    if (fs_mgr_access(super_device)) {
+        *backing_device = super_device;
+        return ScratchStrategy::kDynamicPartition;
+    }
+
+    auto other_slot = fs_mgr_get_other_slot_suffix();
+    if (!other_slot.empty()) {
+        path = kPhysicalDevice + "system" + other_slot;
+        if (fs_mgr_access(path)) {
+            *backing_device = path;
+            return ScratchStrategy::kSystemOther;
         }
     }
-    return scratch_device_cache = path;
+    return ScratchStrategy::kNone;
+}
+
+// Return the scratch device if it exists.
+static std::string GetScratchDevice() {
+    std::string device;
+    ScratchStrategy strategy = GetScratchStrategy(&device);
+
+    switch (strategy) {
+        case ScratchStrategy::kSuperOther:
+        case ScratchStrategy::kSystemOther:
+            return device;
+        case ScratchStrategy::kDynamicPartition: {
+            auto& dm = DeviceMapper::Instance();
+            auto partition_name = android::base::Basename(kScratchMountPoint);
+            if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
+                dm.GetDmDevicePathByName(partition_name, &device)) {
+                return device;
+            }
+            return "";
+        }
+        default:
+            return "";
+    }
+}
+
+std::string fs_mgr_overlayfs_scratch_device() {
+    if (!scratch_device_cache.empty()) return scratch_device_cache;
+
+    scratch_device_cache = GetScratchDevice();
+    return scratch_device_cache;
 }
 
 bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {