fstab: allow mounting other slot

Adding a new fs_mgr flag 'slotselect_other' to mount _b when _a is
active, or vice versa.

Bug: 113182233
Bug: 112103720
Test: `mount_all fstab.test` with one line using `slotselect_other`.

Change-Id: I96c63141df7722dc30ca9817b0b154e493b9eef9
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index d3cd459..bd9d675 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -59,7 +59,7 @@
 
 struct flag_list {
     const char *name;
-    unsigned int flag;
+    uint64_t flag;
 };
 
 static struct flag_list mount_flags[] = {
@@ -116,6 +116,7 @@
         {"logical", MF_LOGICAL},
         {"checkpoint=block", MF_CHECKPOINT_BLK},
         {"checkpoint=fs", MF_CHECKPOINT_FS},
+        {"slotselect_other", MF_SLOTSELECT_OTHER},
         {0, 0},
 };
 
@@ -207,11 +208,9 @@
     return false;
 }
 
-static int parse_flags(char *flags, struct flag_list *fl,
-                       struct fs_mgr_flag_values *flag_vals,
-                       char *fs_options, int fs_options_len)
-{
-    int f = 0;
+static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
+                            char* fs_options, int fs_options_len) {
+    uint64_t f = 0;
     int i;
     char *p;
     char *savep;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 072da97..7d1159b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -120,6 +120,8 @@
 #define MF_CHECKPOINT_FS  0x40000000
 #define MF_FIRST_STAGE_MOUNT \
                           0x80000000
+#define MF_SLOTSELECT_OTHER  \
+                         0x100000000
 // clang-format on
 
 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index efc29bd..3cb718c 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,6 +21,19 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
+// https://source.android.com/devices/tech/ota/ab/ab_implement#partitions
+// All partitions that are A/B-ed should be named as follows (slots are always
+// named a, b, etc.): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+static std::string other_suffix(const std::string& slot_suffix) {
+    if (slot_suffix == "_a") {
+        return "_b";
+    }
+    if (slot_suffix == "_b") {
+        return "_a";
+    }
+    return "";
+}
+
 // Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
 // if that parameter does not exist.
 std::string fs_mgr_get_slot_suffix() {
@@ -35,7 +48,7 @@
     std::string ab_suffix;
 
     for (auto& entry : *fstab) {
-        if (!entry.fs_mgr_flags.slot_select) {
+        if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
             continue;
         }
 
@@ -45,8 +58,10 @@
             if (ab_suffix.empty()) return false;
         }
 
-        entry.blk_device = entry.blk_device + ab_suffix;
-        entry.logical_partition_name = entry.logical_partition_name + ab_suffix;
+        const auto& update_suffix =
+                entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
+        entry.blk_device = entry.blk_device + update_suffix;
+        entry.logical_partition_name = entry.logical_partition_name + update_suffix;
     }
     return true;
 }
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d9a5e0a..0997254 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -43,7 +43,7 @@
     char* fs_type;
     unsigned long flags;
     char* fs_options;
-    int fs_mgr_flags;
+    uint64_t fs_mgr_flags;
     char* key_loc;
     char* key_dir;
     char* verity_loc;
@@ -123,8 +123,9 @@
     // 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.
     union {
-        int val;
+        uint64_t val;
         struct {
+            // bit 0
             bool wait : 1;
             bool check : 1;
             bool crypt : 1;
@@ -133,6 +134,8 @@
             bool length : 1;
             bool recovery_only : 1;
             bool swap_prio : 1;
+
+            // bit 8
             bool zram_size : 1;
             bool verify : 1;
             bool force_crypt : 1;
@@ -142,6 +145,8 @@
             bool file_encryption : 1;
             bool formattable : 1;
             bool slot_select : 1;
+
+            // bit 16
             bool force_fde_or_fbe : 1;
             bool late_mount : 1;
             bool no_fail : 1;
@@ -150,6 +155,8 @@
             bool reserved_size : 1;
             bool quota : 1;
             bool erase_blk_size : 1;
+
+            // bit 24
             bool logical_blk_size : 1;
             bool avb : 1;
             bool key_directory : 1;
@@ -158,6 +165,9 @@
             bool checkpoint_blk : 1;
             bool checkpoint_fs : 1;
             bool first_stage_mount : 1;
+
+            // bit 32
+            bool slot_select_other : 1;
         };
     } fs_mgr_flags;