Merge "adb: Fix incorrect logging statement"
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index aeab893..4f6a8ce 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <array>
 #include <utility>
 #include <vector>
 
@@ -35,146 +36,37 @@
 
 #include "fs_mgr_priv.h"
 
+using android::base::ParseByteCount;
+using android::base::ParseInt;
 using android::base::Split;
 using android::base::StartsWith;
 
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
 
-struct fs_mgr_flag_values {
-    std::string key_loc;
-    std::string key_dir;
-    std::string verity_loc;
-    std::string sysfs_path;
-    std::string zram_loopback_path;
-    uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default
-    std::string zram_backing_dev_path;
-    off64_t part_length = 0;
-    std::string label;
-    int partnum = -1;
-    int swap_prio = -1;
-    int max_comp_streams = 0;
-    off64_t zram_size = 0;
-    off64_t reserved_size = 0;
-    int file_contents_mode = 0;
-    int file_names_mode = 0;
-    off64_t erase_blk_size = 0;
-    off64_t logical_blk_size = 0;
-    std::string vbmeta_partition;
-};
-
 struct flag_list {
     const char *name;
     uint64_t flag;
 };
 
-static struct flag_list mount_flags[] = {
-    { "noatime",    MS_NOATIME },
-    { "noexec",     MS_NOEXEC },
-    { "nosuid",     MS_NOSUID },
-    { "nodev",      MS_NODEV },
-    { "nodiratime", MS_NODIRATIME },
-    { "ro",         MS_RDONLY },
-    { "rw",         0 },
-    { "remount",    MS_REMOUNT },
-    { "bind",       MS_BIND },
-    { "rec",        MS_REC },
-    { "unbindable", MS_UNBINDABLE },
-    { "private",    MS_PRIVATE },
-    { "slave",      MS_SLAVE },
-    { "shared",     MS_SHARED },
-    { "defaults",   0 },
-    { 0,            0 },
-};
-
-static struct flag_list fs_mgr_flags[] = {
-        {"wait", MF_WAIT},
-        {"check", MF_CHECK},
-        {"encryptable=", MF_CRYPT},
-        {"forceencrypt=", MF_FORCECRYPT},
-        {"fileencryption=", MF_FILEENCRYPTION},
-        {"forcefdeorfbe=", MF_FORCEFDEORFBE},
-        {"keydirectory=", MF_KEYDIRECTORY},
-        {"nonremovable", MF_NONREMOVABLE},
-        {"voldmanaged=", MF_VOLDMANAGED},
-        {"length=", MF_LENGTH},
-        {"recoveryonly", MF_RECOVERYONLY},
-        {"swapprio=", MF_SWAPPRIO},
-        {"zramsize=", MF_ZRAMSIZE},
-        {"max_comp_streams=", MF_MAX_COMP_STREAMS},
-        {"verifyatboot", MF_VERIFYATBOOT},
-        {"verify", MF_VERIFY},
-        {"avb", MF_AVB},
-        {"avb=", MF_AVB},
-        {"noemulatedsd", MF_NOEMULATEDSD},
-        {"notrim", MF_NOTRIM},
-        {"formattable", MF_FORMATTABLE},
-        {"slotselect", MF_SLOTSELECT},
-        {"nofail", MF_NOFAIL},
-        {"first_stage_mount", MF_FIRST_STAGE_MOUNT},
-        {"latemount", MF_LATEMOUNT},
-        {"reservedsize=", MF_RESERVEDSIZE},
-        {"quota", MF_QUOTA},
-        {"eraseblk=", MF_ERASEBLKSIZE},
-        {"logicalblk=", MF_LOGICALBLKSIZE},
-        {"sysfs_path=", MF_SYSFS},
+static struct flag_list mount_flags_list[] = {
+        {"noatime", MS_NOATIME},
+        {"noexec", MS_NOEXEC},
+        {"nosuid", MS_NOSUID},
+        {"nodev", MS_NODEV},
+        {"nodiratime", MS_NODIRATIME},
+        {"ro", MS_RDONLY},
+        {"rw", 0},
+        {"remount", MS_REMOUNT},
+        {"bind", MS_BIND},
+        {"rec", MS_REC},
+        {"unbindable", MS_UNBINDABLE},
+        {"private", MS_PRIVATE},
+        {"slave", MS_SLAVE},
+        {"shared", MS_SHARED},
         {"defaults", 0},
-        {"logical", MF_LOGICAL},
-        {"checkpoint=block", MF_CHECKPOINT_BLK},
-        {"checkpoint=fs", MF_CHECKPOINT_FS},
-        {"slotselect_other", MF_SLOTSELECT_OTHER},
-        {"zram_loopback_path=", MF_ZRAM_LOOPBACK_PATH},
-        {"zram_loopback_size=", MF_ZRAM_LOOPBACK_SIZE},
-        {"zram_backing_dev_path=", MF_ZRAM_BACKING_DEV_PATH},
-        {"fsverity", MF_FS_VERITY},
-        {0, 0},
 };
 
-#define EM_AES_256_XTS  1
-#define EM_ICE          2
-#define EM_AES_256_CTS  3
-#define EM_AES_256_HEH  4
-#define EM_ADIANTUM     5
-
-static const struct flag_list file_contents_encryption_modes[] = {
-    {"aes-256-xts", EM_AES_256_XTS},
-    {"adiantum", EM_ADIANTUM},
-    {"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
-    {"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
-    {0, 0},
-};
-
-static const struct flag_list file_names_encryption_modes[] = {
-    {"aes-256-cts", EM_AES_256_CTS},
-    {"aes-256-heh", EM_AES_256_HEH},
-    {"adiantum", EM_ADIANTUM},
-    {0, 0},
-};
-
-static int encryption_mode_to_flag(const struct flag_list* list, const char* mode,
-                                   const char* type) {
-    const struct flag_list *j;
-
-    for (j = list; j->name; ++j) {
-        if (!strcmp(mode, j->name)) {
-            return j->flag;
-        }
-    }
-    LERROR << "Unknown " << type << " encryption mode: " << mode;
-    return 0;
-}
-
-static const char* flag_to_encryption_mode(const struct flag_list* list, uint64_t flag) {
-    const struct flag_list *j;
-
-    for (j = list; j->name; ++j) {
-        if (flag == j->flag) {
-            return j->name;
-        }
-    }
-    return nullptr;
-}
-
-static off64_t calculate_zram_size(unsigned int percentage) {
+static off64_t calculate_zram_size(int percentage) {
     off64_t total;
 
     total  = sysconf(_SC_PHYS_PAGES);
@@ -186,19 +78,6 @@
     return total;
 }
 
-static off64_t parse_size(const char* arg) {
-    char *endptr;
-    off64_t size = strtoll(arg, &endptr, 10);
-    if (*endptr == 'k' || *endptr == 'K')
-        size *= 1024LL;
-    else if (*endptr == 'm' || *endptr == 'M')
-        size *= 1024LL * 1024LL;
-    else if (*endptr == 'g' || *endptr == 'G')
-        size *= 1024LL * 1024LL * 1024LL;
-
-    return size;
-}
-
 /* fills 'dt_value' with the underlying device tree value string without
  * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
  * otherwise.
@@ -217,174 +96,252 @@
     return false;
 }
 
-static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
-                            std::string* fs_options) {
-    uint64_t f = 0;
-    int i;
-    char *p;
-    char *savep;
+const static std::array<const char*, 3> kFileContentsEncryptionMode = {
+        "aes-256-xts",
+        "adiantum",
+        "ice",
+};
 
-    p = strtok_r(flags, ",", &savep);
-    while (p) {
-        /* Look for the flag "p" in the flag list "fl"
-         * If not found, the loop exits with fl[i].name being null.
-         */
-        for (i = 0; fl[i].name; i++) {
-            auto name = fl[i].name;
-            auto len = strlen(name);
-            auto end = len;
-            if (name[end - 1] == '=') --end;
-            if (!strncmp(p, name, len) && (p[end] == name[end])) {
-                f |= fl[i].flag;
-                if (!flag_vals) break;
-                if (p[end] != '=') break;
-                char* arg = p + end + 1;
-                auto flag = fl[i].flag;
-                if (flag == MF_CRYPT) {
-                    /* The encryptable flag is followed by an = and the
-                     * location of the keys.  Get it and return it.
-                     */
-                    flag_vals->key_loc = arg;
-                } else if (flag == MF_VERIFY) {
-                    /* If the verify flag is followed by an = and the
-                     * location for the verity state,  get it and return it.
-                     */
-                    flag_vals->verity_loc = arg;
-                } else if (flag == MF_FORCECRYPT) {
-                    /* The forceencrypt flag is followed by an = and the
-                     * location of the keys.  Get it and return it.
-                     */
-                    flag_vals->key_loc = arg;
-                } else if (flag == MF_FORCEFDEORFBE) {
-                    /* The forcefdeorfbe flag is followed by an = and the
-                     * location of the keys.  Get it and return it.
-                     */
-                    flag_vals->key_loc = arg;
-                    flag_vals->file_contents_mode = EM_AES_256_XTS;
-                    flag_vals->file_names_mode = EM_AES_256_CTS;
-                } else if (flag == MF_FILEENCRYPTION) {
-                    /* The fileencryption flag is followed by an = and
-                     * the mode of contents encryption, then optionally a
-                     * : and the mode of filenames encryption (defaults
-                     * to aes-256-cts).  Get it and return it.
-                     */
-                    auto mode = arg;
-                    auto colon = strchr(mode, ':');
-                    if (colon) {
-                        *colon = '\0';
-                    }
-                    flag_vals->file_contents_mode =
-                        encryption_mode_to_flag(file_contents_encryption_modes,
-                                                mode, "file contents");
-                    if (colon) {
-                        flag_vals->file_names_mode =
-                            encryption_mode_to_flag(file_names_encryption_modes,
-                                                    colon + 1, "file names");
-                    } else if (flag_vals->file_contents_mode == EM_ADIANTUM) {
-                        flag_vals->file_names_mode = EM_ADIANTUM;
-                    } else {
-                        flag_vals->file_names_mode = EM_AES_256_CTS;
-                    }
-                } else if (flag == MF_KEYDIRECTORY) {
-                    /* The metadata flag is followed by an = and the
-                     * directory for the keys.  Get it and return it.
-                     */
-                    flag_vals->key_dir = arg;
-                } else if (flag == MF_LENGTH) {
-                    /* The length flag is followed by an = and the
-                     * size of the partition.  Get it and return it.
-                     */
-                    flag_vals->part_length = strtoll(arg, NULL, 0);
-                } else if (flag == MF_VOLDMANAGED) {
-                    /* The voldmanaged flag is followed by an = and the
-                     * label, a colon and the partition number or the
-                     * word "auto", e.g.
-                     *   voldmanaged=sdcard:3
-                     * Get and return them.
-                     */
-                    auto label_start = arg;
-                    auto label_end = strchr(label_start, ':');
+const static std::array<const char*, 3> kFileNamesEncryptionMode = {
+        "aes-256-cts",
+        "aes-256-heh",
+        "adiantum",
+};
 
-                    if (label_end) {
-                        flag_vals->label = std::string(label_start, (int)(label_end - label_start));
-                        auto part_start = label_end + 1;
-                        if (!strcmp(part_start, "auto")) {
-                            flag_vals->partnum = -1;
-                        } else {
-                            flag_vals->partnum = strtol(part_start, NULL, 0);
-                        }
-                    } else {
-                        LERROR << "Warning: voldmanaged= flag malformed";
-                    }
-                } else if (flag == MF_SWAPPRIO) {
-                    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);
-                    if (is_percent)
-                        flag_vals->zram_size = calculate_zram_size(val);
-                    else
-                        flag_vals->zram_size = val;
-                } else if (flag == MF_RESERVEDSIZE) {
-                    /* The reserved flag is followed by an = and the
-                     * reserved size of the partition.  Get it and return it.
-                     */
-                    flag_vals->reserved_size = parse_size(arg);
-                } else if (flag == MF_ERASEBLKSIZE) {
-                    /* The erase block size flag is followed by an = and the flash
-                     * erase block size. Get it, check that it is a power of 2 and
-                     * at least 4096, and return it.
-                     */
-                    auto val = strtoll(arg, nullptr, 0);
-                    if (val >= 4096 && (val & (val - 1)) == 0)
-                        flag_vals->erase_blk_size = val;
-                } else if (flag == MF_LOGICALBLKSIZE) {
-                    /* The logical block size flag is followed by an = and the flash
-                     * logical block size. Get it, check that it is a power of 2 and
-                     * at least 4096, and return it.
-                     */
-                    auto val = strtoll(arg, nullptr, 0);
-                    if (val >= 4096 && (val & (val - 1)) == 0)
-                        flag_vals->logical_blk_size = val;
-                } else if (flag == MF_SYSFS) {
-                    /* The path to trigger device gc by idle-maint of vold. */
-                    flag_vals->sysfs_path = arg;
-                } else if (flag == MF_ZRAM_LOOPBACK_PATH) {
-                    /* The path to use loopback for zram. */
-                    flag_vals->zram_loopback_path = arg;
-                } else if (flag == MF_ZRAM_LOOPBACK_SIZE) {
-                    if (!android::base::ParseByteCount(arg, &flag_vals->zram_loopback_size)) {
-                        LERROR << "Warning: zram_loopback_size = flag malformed";
-                    }
-                } else if (flag == MF_ZRAM_BACKING_DEV_PATH) {
-                    /* The path to use loopback for zram. */
-                    flag_vals->zram_backing_dev_path = arg;
-                }
-                break;
-            }
-        }
+static void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
+    // The fileencryption flag is followed by an = and the mode of contents encryption, then
+    // optionally a and the mode of filenames encryption (defaults to aes-256-cts).  Get it and
+    // return it.
+    entry->fs_mgr_flags.file_encryption = true;
 
-        if (!fl[i].name) {
-            if (fs_options) {
-                // It's not a known flag, so it must be a filesystem specific
-                // option.  Add it to fs_options if it was passed in.
-                if (!fs_options->empty()) {
-                    fs_options->append(",");  // appends a comma if not the first
-                }
-                fs_options->append(p);
-            } else {
-                // fs_options was not passed in, so if the flag is unknown it's an error.
-                LERROR << "Warning: unknown flag " << p;
-            }
-        }
-        p = strtok_r(NULL, ",", &savep);
+    auto parts = Split(arg, ":");
+    if (parts.empty() || parts.size() > 2) {
+        LWARNING << "Warning: fileencryption= flag malformed: " << arg;
+        return;
     }
 
-    return f;
+    // Alias for backwards compatibility.
+    if (parts[0] == "software") {
+        parts[0] = "aes-256-xts";
+    }
+
+    if (std::find(kFileContentsEncryptionMode.begin(), kFileContentsEncryptionMode.end(),
+                  parts[0]) == kFileContentsEncryptionMode.end()) {
+        LWARNING << "fileencryption= flag malformed, file contents encryption mode not found: "
+                 << arg;
+        return;
+    }
+
+    entry->file_contents_mode = parts[0];
+
+    if (parts.size() == 2) {
+        if (std::find(kFileNamesEncryptionMode.begin(), kFileNamesEncryptionMode.end(), parts[1]) ==
+            kFileNamesEncryptionMode.end()) {
+            LWARNING << "fileencryption= flag malformed, file names encryption mode not found: "
+                     << arg;
+            return;
+        }
+
+        entry->file_names_mode = parts[1];
+    } else if (entry->file_contents_mode == "adiantum") {
+        entry->file_names_mode = "adiantum";
+    } else {
+        entry->file_names_mode = "aes-256-cts";
+    }
+}
+
+static bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
+    for (const auto& [name, value] : mount_flags_list) {
+        if (flag == name) {
+            entry->flags |= value;
+            return true;
+        }
+    }
+    return false;
+}
+
+static void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
+    std::string fs_options;
+    for (const auto& flag : Split(flags, ",")) {
+        if (!SetMountFlag(flag, entry)) {
+            // Unknown flag, so it must be a filesystem specific option.
+            if (!fs_options.empty()) {
+                fs_options.append(",");  // appends a comma if not the first
+            }
+            fs_options.append(flag);
+        }
+    }
+    entry->fs_options = std::move(fs_options);
+}
+
+static void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
+    entry->fs_mgr_flags.val = 0U;
+    for (const auto& flag : Split(flags, ",")) {
+        std::string arg;
+        if (auto equal_sign = flag.find('='); equal_sign != std::string::npos) {
+            arg = flag.substr(equal_sign + 1);
+        }
+
+        // First handle flags that simply set a boolean.
+#define CheckFlag(flag_name, value)       \
+    if (flag == flag_name) {              \
+        entry->fs_mgr_flags.value = true; \
+        continue;                         \
+    }
+
+        CheckFlag("wait", wait);
+        CheckFlag("check", check);
+        CheckFlag("nonremovable", nonremovable);
+        CheckFlag("recoveryonly", recovery_only);
+        CheckFlag("noemulatedsd", no_emulated_sd);
+        CheckFlag("notrim", no_trim);
+        CheckFlag("verify", verify);
+        CheckFlag("formattable", formattable);
+        CheckFlag("slotselect", slot_select);
+        CheckFlag("latemount", late_mount);
+        CheckFlag("nofail", no_fail);
+        CheckFlag("verifyatboot", verify_at_boot);
+        CheckFlag("quota", quota);
+        CheckFlag("avb", avb);
+        CheckFlag("logical", logical);
+        CheckFlag("checkpoint=block", checkpoint_blk);
+        CheckFlag("checkpoint=fs", checkpoint_fs);
+        CheckFlag("first_stage_mount", first_stage_mount);
+        CheckFlag("slotselect_other", slot_select_other);
+        CheckFlag("fsverity", fs_verity);
+
+#undef CheckFlag
+
+        // Then handle flags that take an argument.
+        if (StartsWith(flag, "encryptable=")) {
+            // The encryptable flag is followed by an = and the  location of the keys.
+            entry->fs_mgr_flags.crypt = true;
+            entry->key_loc = arg;
+        } else if (StartsWith(flag, "voldmanaged=")) {
+            // The voldmanaged flag is followed by an = and the label, a colon and the partition
+            // number or the word "auto", e.g. voldmanaged=sdcard:3
+            entry->fs_mgr_flags.vold_managed = true;
+            auto parts = Split(arg, ":");
+            if (parts.size() != 2) {
+                LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
+                continue;
+            }
+
+            entry->label = std::move(parts[0]);
+            if (parts[1] == "auto") {
+                entry->partnum = -1;
+            } else {
+                if (!ParseInt(parts[1], &entry->partnum)) {
+                    entry->partnum = -1;
+                    LWARNING << "Warning: voldmanaged= flag malformed: " << arg;
+                    continue;
+                }
+            }
+        } else if (StartsWith(flag, "length=")) {
+            // The length flag is followed by an = and the size of the partition.
+            entry->fs_mgr_flags.length = true;
+            if (!ParseInt(arg, &entry->length)) {
+                LWARNING << "Warning: length= flag malformed: " << arg;
+            }
+        } else if (StartsWith(flag, "swapprio=")) {
+            entry->fs_mgr_flags.swap_prio = true;
+            if (!ParseInt(arg, &entry->swap_prio)) {
+                LWARNING << "Warning: length= flag malformed: " << arg;
+            }
+        } else if (StartsWith(flag, "zramsize=")) {
+            entry->fs_mgr_flags.zram_size = true;
+
+            if (!arg.empty() && arg.back() == '%') {
+                arg.pop_back();
+                int val;
+                if (ParseInt(arg, &val, 0, 100)) {
+                    entry->zram_size = calculate_zram_size(val);
+                } else {
+                    LWARNING << "Warning: zramsize= flag malformed: " << arg;
+                }
+            } else {
+                if (!ParseInt(arg, &entry->zram_size)) {
+                    LWARNING << "Warning: zramsize= flag malformed: " << arg;
+                }
+            }
+        } else if (StartsWith(flag, "verify=")) {
+            // If the verify flag is followed by an = and the location for the verity state.
+            entry->fs_mgr_flags.verify = true;
+            entry->verity_loc = arg;
+        } else if (StartsWith(flag, "forceencrypt=")) {
+            // The forceencrypt flag is followed by an = and the location of the keys.
+            entry->fs_mgr_flags.force_crypt = true;
+            entry->key_loc = arg;
+        } else if (StartsWith(flag, "fileencryption=")) {
+            ParseFileEncryption(arg, entry);
+        } else if (StartsWith(flag, "forcefdeorfbe=")) {
+            // The forcefdeorfbe flag is followed by an = and the location of the keys.  Get it and
+            // return it.
+            entry->fs_mgr_flags.force_fde_or_fbe = true;
+            entry->key_loc = arg;
+            entry->file_contents_mode = "aes-256-xts";
+            entry->file_names_mode = "aes-256-cts";
+        } else if (StartsWith(flag, "max_comp_streams=")) {
+            entry->fs_mgr_flags.max_comp_streams = true;
+            if (!ParseInt(arg, &entry->max_comp_streams)) {
+                LWARNING << "Warning: max_comp_streams= flag malformed: " << arg;
+            }
+        } else if (StartsWith(flag, "reservedsize=")) {
+            // The reserved flag is followed by an = and the reserved size of the partition.
+            entry->fs_mgr_flags.reserved_size = true;
+            uint64_t size;
+            if (!ParseByteCount(arg, &size)) {
+                LWARNING << "Warning: reservedsize= flag malformed: " << arg;
+            } else {
+                entry->reserved_size = static_cast<off64_t>(size);
+            }
+        } else if (StartsWith(flag, "eraseblk=")) {
+            // The erase block size flag is followed by an = and the flash erase block size. Get it,
+            // check that it is a power of 2 and at least 4096, and return it.
+            entry->fs_mgr_flags.erase_blk_size = true;
+            off64_t val;
+            if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
+                LWARNING << "Warning: eraseblk= flag malformed: " << arg;
+            } else {
+                entry->erase_blk_size = val;
+            }
+        } else if (StartsWith(flag, "logicalblk=")) {
+            // The logical block size flag is followed by an = and the flash logical block size. Get
+            // it, check that it is a power of 2 and at least 4096, and return it.
+            entry->fs_mgr_flags.logical_blk_size = true;
+            off64_t val;
+            if (!ParseInt(arg, &val) || val < 4096 || (val & (val - 1)) != 0) {
+                LWARNING << "Warning: logicalblk= flag malformed: " << arg;
+            } else {
+                entry->logical_blk_size = val;
+            }
+        } else if (StartsWith(flag, "avb")) {
+            entry->fs_mgr_flags.avb = true;
+            entry->vbmeta_partition = arg;
+        } else if (StartsWith(flag, "keydirectory=")) {
+            // The metadata flag is followed by an = and the directory for the keys.
+            entry->fs_mgr_flags.key_directory = true;
+            entry->key_dir = arg;
+        } else if (StartsWith(flag, "sysfs_path=")) {
+            // The path to trigger device gc by idle-maint of vold.
+            entry->fs_mgr_flags.sysfs = true;
+            entry->sysfs_path = arg;
+        } else if (StartsWith(flag, "zram_loopback_path=")) {
+            // The path to use loopback for zram.
+            entry->fs_mgr_flags.zram_loopback_path = true;
+            entry->zram_loopback_path = arg;
+        } else if (StartsWith(flag, "zram_loopback_size=")) {
+            entry->fs_mgr_flags.zram_loopback_size = true;
+            if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
+                LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
+            }
+        } else if (StartsWith(flag, "zram_backing_dev_path=")) {
+            entry->fs_mgr_flags.zram_backing_dev_path = true;
+            entry->zram_backing_dev_path = arg;
+        } else {
+            LWARNING << "Warning: unknown flag: " << flag;
+        }
+    }
 }
 
 static std::string init_android_dt_dir() {
@@ -520,7 +477,6 @@
     const char *delim = " \t";
     char *save_ptr, *p;
     Fstab fstab;
-    struct fs_mgr_flag_values flag_vals;
 
     while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {
         /* if the last character is a newline, shorten the string by 1 byte */
@@ -561,7 +517,8 @@
             LERROR << "Error parsing mount_flags";
             goto err;
         }
-        entry.flags = parse_flags(p, mount_flags, nullptr, &entry.fs_options);
+
+        ParseMountFlags(p, &entry);
 
         // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
         if (proc_mounts) {
@@ -570,27 +527,9 @@
             LERROR << "Error parsing fs_mgr_options";
             goto err;
         }
-        entry.fs_mgr_flags.val = parse_flags(p, fs_mgr_flags, &flag_vals, nullptr);
 
-        entry.key_loc = std::move(flag_vals.key_loc);
-        entry.key_dir = std::move(flag_vals.key_dir);
-        entry.verity_loc = std::move(flag_vals.verity_loc);
-        entry.length = flag_vals.part_length;
-        entry.label = std::move(flag_vals.label);
-        entry.partnum = flag_vals.partnum;
-        entry.swap_prio = flag_vals.swap_prio;
-        entry.max_comp_streams = flag_vals.max_comp_streams;
-        entry.zram_size = flag_vals.zram_size;
-        entry.reserved_size = flag_vals.reserved_size;
-        entry.file_contents_mode = flag_vals.file_contents_mode;
-        entry.file_names_mode = flag_vals.file_names_mode;
-        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);
-        entry.zram_loopback_path = std::move(flag_vals.zram_loopback_path);
-        entry.zram_loopback_size = std::move(flag_vals.zram_loopback_size);
-        entry.zram_backing_dev_path = std::move(flag_vals.zram_backing_dev_path);
+        ParseFsMgrFlags(p, &entry);
+
         if (entry.fs_mgr_flags.logical) {
             entry.logical_partition_name = entry.blk_device;
         }
@@ -834,6 +773,8 @@
         free(fstab->recs[i].key_loc);
         free(fstab->recs[i].key_dir);
         free(fstab->recs[i].label);
+        free(fstab->recs[i].file_contents_mode);
+        free(fstab->recs[i].file_names_mode);
         free(fstab->recs[i].sysfs_path);
         free(fstab->recs[i].zram_loopback_path);
         free(fstab->recs[i].zram_backing_dev_path);
@@ -975,8 +916,8 @@
         legacy_fstab->recs[i].max_comp_streams = fstab[i].max_comp_streams;
         legacy_fstab->recs[i].zram_size = fstab[i].zram_size;
         legacy_fstab->recs[i].reserved_size = fstab[i].reserved_size;
-        legacy_fstab->recs[i].file_contents_mode = fstab[i].file_contents_mode;
-        legacy_fstab->recs[i].file_names_mode = fstab[i].file_names_mode;
+        legacy_fstab->recs[i].file_contents_mode = strdup(fstab[i].file_contents_mode.c_str());
+        legacy_fstab->recs[i].file_names_mode = strdup(fstab[i].file_names_mode.c_str());
         legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
         legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
         legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
@@ -1022,14 +963,10 @@
     return fstab->fs_mgr_flags & MF_FILEENCRYPTION;
 }
 
-void fs_mgr_get_file_encryption_modes(const struct fstab_rec *fstab,
-                                      const char **contents_mode_ret,
-                                      const char **filenames_mode_ret)
-{
-    *contents_mode_ret = flag_to_encryption_mode(file_contents_encryption_modes,
-                                                 fstab->file_contents_mode);
-    *filenames_mode_ret = flag_to_encryption_mode(file_names_encryption_modes,
-                                                  fstab->file_names_mode);
+void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
+                                      const char** filenames_mode_ret) {
+    *contents_mode_ret = fstab->file_contents_mode;
+    *filenames_mode_ret = fstab->file_names_mode;
 }
 
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec *fstab)
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 9c4d2da..88ecec0 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -54,8 +54,8 @@
     int max_comp_streams;
     off64_t zram_size;
     off64_t reserved_size;
-    int file_contents_mode;
-    int file_names_mode;
+    char* file_contents_mode;
+    char* file_names_mode;
     off64_t erase_blk_size;
     off64_t logical_blk_size;
     char* sysfs_path;
@@ -118,19 +118,19 @@
     int max_comp_streams = 0;
     off64_t zram_size = 0;
     off64_t reserved_size = 0;
-    int file_contents_mode = 0;
-    int file_names_mode = 0;
+    std::string file_contents_mode;
+    std::string file_names_mode;
     off64_t erase_blk_size = 0;
     off64_t logical_blk_size = 0;
     std::string sysfs_path;
     std::string vbmeta_partition;
     std::string zram_loopback_path;
-    uint64_t zram_loopback_size;
+    uint64_t zram_loopback_size = 512 * 1024 * 1024;  // 512MB by default;
     std::string zram_backing_dev_path;
 
     // 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 {
+    union FsMgrFlags {
         uint64_t val;
         struct {
             // bit 0
diff --git a/fs_mgr/tests/data/fstab.example b/fs_mgr/tests/data/fstab.example
index 1a3dfa1..aebce32 100644
--- a/fs_mgr/tests/data/fstab.example
+++ b/fs_mgr/tests/data/fstab.example
@@ -9,3 +9,7 @@
 /dev/block/bootdevice/by-name/modem                 /vendor/firmware_mnt          vfat        ro,shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0   wait,slotselect
 /devices/platform/soc/a600000.ssusb/a600000.dwc3*   auto               vfat        defaults                                              voldmanaged=usb:auto
 /dev/block/zram0                                    none               swap        defaults                                              zramsize=1073741824,max_comp_streams=8
+/dev/block/zram0                                    none2              swap        nodiratime,remount,bind                               zramsize=1073741824,max_comp_streams=8
+/dev/block/zram0                                    none3              swap        unbindable,private,slave                              zramsize=1073741824,max_comp_streams=8
+/dev/block/zram0                                    none4              swap        noexec,shared,rec                                     zramsize=1073741824,max_comp_streams=8
+/dev/block/zram0                                    none5              swap        rw                                                    zramsize=1073741824,max_comp_streams=8
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 4582401..e2b283a 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -201,32 +201,823 @@
     EXPECT_EQ(i, fstab.size());
 }
 
-TEST(fs_mgr, ReadFstabFromFile_FsOptions) {
+TEST(fs_mgr, ReadFstabFromFile_MountOptions) {
     Fstab fstab;
     std::string fstab_file = android::base::GetExecutableDirectory() + "/data/fstab.example";
     EXPECT_TRUE(ReadFstabFromFile(fstab_file, &fstab));
 
     EXPECT_EQ("/", fstab[0].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_RDONLY), fstab[0].flags);
     EXPECT_EQ("barrier=1", fstab[0].fs_options);
 
     EXPECT_EQ("/metadata", fstab[1].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_NOATIME | MS_NOSUID | MS_NODEV), fstab[1].flags);
     EXPECT_EQ("discard", fstab[1].fs_options);
 
     EXPECT_EQ("/data", fstab[2].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_NOATIME | MS_NOSUID | MS_NODEV), fstab[2].flags);
     EXPECT_EQ("discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier", fstab[2].fs_options);
 
     EXPECT_EQ("/misc", fstab[3].mount_point);
+    EXPECT_EQ(0U, fstab[3].flags);
     EXPECT_EQ("", fstab[3].fs_options);
 
     EXPECT_EQ("/vendor/firmware_mnt", fstab[4].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_RDONLY), fstab[4].flags);
     EXPECT_EQ(
             "shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,"
             "context=u:object_r:firmware_file:s0",
             fstab[4].fs_options);
 
     EXPECT_EQ("auto", fstab[5].mount_point);
+    EXPECT_EQ(0U, fstab[5].flags);
     EXPECT_EQ("", fstab[5].fs_options);
 
     EXPECT_EQ("none", fstab[6].mount_point);
+    EXPECT_EQ(0U, fstab[6].flags);
     EXPECT_EQ("", fstab[6].fs_options);
+
+    EXPECT_EQ("none2", fstab[7].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_NODIRATIME | MS_REMOUNT | MS_BIND), fstab[7].flags);
+    EXPECT_EQ("", fstab[7].fs_options);
+
+    EXPECT_EQ("none3", fstab[8].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE), fstab[8].flags);
+    EXPECT_EQ("", fstab[8].fs_options);
+
+    EXPECT_EQ("none4", fstab[9].mount_point);
+    EXPECT_EQ(static_cast<unsigned long>(MS_NOEXEC | MS_SHARED | MS_REC), fstab[9].flags);
+    EXPECT_EQ("", fstab[9].fs_options);
+
+    EXPECT_EQ("none5", fstab[10].mount_point);
+    EXPECT_EQ(0U, fstab[10].flags);  // rw is the same as defaults
+    EXPECT_EQ("", fstab[10].fs_options);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrFlags) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      wait,check,nonremovable,recoveryonly,verifyatboot,verify
+source none1       swap   defaults      avb,noemulatedsd,notrim,formattable,slotselect,nofail
+source none2       swap   defaults      first_stage_mount,latemount,quota,logical,slotselect_other
+source none3       swap   defaults      checkpoint=block
+source none4       swap   defaults      checkpoint=fs
+source none5       swap   defaults      defaults
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(6U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.wait = true;
+        flags.check = true;
+        flags.nonremovable = true;
+        flags.recovery_only = true;
+        flags.verify_at_boot = true;
+        flags.verify = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.avb = true;
+        flags.no_emulated_sd = true;
+        flags.no_trim = true;
+        flags.formattable = true;
+        flags.slot_select = true;
+        flags.no_fail = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.first_stage_mount = true;
+        flags.late_mount = true;
+        flags.quota = true;
+        flags.logical = true;
+        flags.slot_select_other = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.checkpoint_blk = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    entry++;
+
+    EXPECT_EQ("none4", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.checkpoint_fs = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    entry++;
+
+    EXPECT_EQ("none5", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_AllBad) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_loopback_path,zram_loopback_size,zram_backing_dev_path
+
+source none1       swap   defaults      encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,verify=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_loopback_path=,zram_loopback_size=,zram_backing_dev_path=
+
+source none2       swap   defaults      forcefdeorfbe=
+
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(3U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    EXPECT_EQ("", entry->key_loc);
+    EXPECT_EQ("", entry->key_dir);
+    EXPECT_EQ("", entry->verity_loc);
+    EXPECT_EQ(0, entry->length);
+    EXPECT_EQ("", entry->label);
+    EXPECT_EQ(-1, entry->partnum);
+    EXPECT_EQ(-1, entry->swap_prio);
+    EXPECT_EQ(0, entry->max_comp_streams);
+    EXPECT_EQ(0, entry->zram_size);
+    EXPECT_EQ(0, entry->reserved_size);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+    EXPECT_EQ(0, entry->erase_blk_size);
+    EXPECT_EQ(0, entry->logical_blk_size);
+    EXPECT_EQ("", entry->sysfs_path);
+    EXPECT_EQ("", entry->zram_loopback_path);
+    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
+    EXPECT_EQ("", entry->zram_backing_dev_path);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.crypt = true;
+        flags.force_crypt = true;
+        flags.file_encryption = true;
+        flags.key_directory = true;
+        flags.length = true;
+        flags.swap_prio = true;
+        flags.zram_size = true;
+        flags.max_comp_streams = true;
+        flags.verify = true;
+        flags.avb = true;
+        flags.reserved_size = true;
+        flags.erase_blk_size = true;
+        flags.logical_blk_size = true;
+        flags.sysfs = true;
+        flags.zram_loopback_path = true;
+        flags.zram_loopback_size = true;
+        flags.zram_backing_dev_path = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    EXPECT_EQ("", entry->key_loc);
+    EXPECT_EQ("", entry->key_dir);
+    EXPECT_EQ("", entry->verity_loc);
+    EXPECT_EQ(0, entry->length);
+    EXPECT_EQ("", entry->label);
+    EXPECT_EQ(-1, entry->partnum);
+    EXPECT_EQ(-1, entry->swap_prio);
+    EXPECT_EQ(0, entry->max_comp_streams);
+    EXPECT_EQ(0, entry->zram_size);
+    EXPECT_EQ(0, entry->reserved_size);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+    EXPECT_EQ(0, entry->erase_blk_size);
+    EXPECT_EQ(0, entry->logical_blk_size);
+    EXPECT_EQ("", entry->sysfs_path);
+    EXPECT_EQ("", entry->zram_loopback_path);
+    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
+    EXPECT_EQ("", entry->zram_backing_dev_path);
+    entry++;
+
+    // forcefdeorfbe sets file_contents_mode and file_names_mode by default, so test it separately.
+    EXPECT_EQ("none2", entry->mount_point);
+    {
+        FstabEntry::FsMgrFlags flags = {0};
+        flags.force_fde_or_fbe = true;
+        EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    }
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+    EXPECT_EQ("", entry->key_loc);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Encryptable) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      encryptable=/dir/key
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.crypt = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("/dir/key", entry->key_loc);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_VoldManaged) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      voldmanaged=:
+source none1       swap   defaults      voldmanaged=sdcard
+source none2       swap   defaults      voldmanaged=sdcard:3
+source none3       swap   defaults      voldmanaged=sdcard:auto
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(4U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.vold_managed = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_TRUE(entry->label.empty());
+    EXPECT_EQ(-1, entry->partnum);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_TRUE(entry->label.empty());
+    EXPECT_EQ(-1, entry->partnum);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("sdcard", entry->label);
+    EXPECT_EQ(3, entry->partnum);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("sdcard", entry->label);
+    EXPECT_EQ(-1, entry->partnum);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Length) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      length=blah
+source none1       swap   defaults      length=123456
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(2U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.length = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->length);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(123456, entry->length);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Swapprio) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      swapprio=blah
+source none1       swap   defaults      swapprio=123456
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(2U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.swap_prio = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(-1, entry->swap_prio);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(123456, entry->swap_prio);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ZramSize) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      zramsize=blah
+source none1       swap   defaults      zramsize=123456
+source none2       swap   defaults      zramsize=blah%
+source none3       swap   defaults      zramsize=5%
+source none4       swap   defaults      zramsize=105%
+source none5       swap   defaults      zramsize=%
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(6U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.zram_size = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->zram_size);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(123456, entry->zram_size);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->zram_size);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_NE(0, entry->zram_size);
+    entry++;
+
+    EXPECT_EQ("none4", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->zram_size);
+    entry++;
+
+    EXPECT_EQ("none5", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->zram_size);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Verify) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      verify=/dir/key
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.verify = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/dir/key", entry->verity_loc);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceEncrypt) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      forceencrypt=/dir/key
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.force_crypt = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/dir/key", entry->key_loc);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceFdeOrFbe) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      forcefdeorfbe=/dir/key
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.force_fde_or_fbe = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/dir/key", entry->key_loc);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      fileencryption=blah
+source none1       swap   defaults      fileencryption=software
+source none2       swap   defaults      fileencryption=aes-256-xts
+source none3       swap   defaults      fileencryption=adiantum
+source none4       swap   defaults      fileencryption=adiantum:aes-256-heh
+source none5       swap   defaults      fileencryption=ice
+source none6       swap   defaults      fileencryption=ice:blah
+source none7       swap   defaults      fileencryption=ice:aes-256-cts
+source none8       swap   defaults      fileencryption=ice:aes-256-heh
+source none9       swap   defaults      fileencryption=ice:adiantum
+source none10      swap   defaults      fileencryption=ice:adiantum:
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(11U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.file_encryption = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("aes-256-xts", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("adiantum", entry->file_contents_mode);
+    EXPECT_EQ("adiantum", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none4", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("adiantum", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none5", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none6", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none7", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-cts", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none8", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("aes-256-heh", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none9", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("ice", entry->file_contents_mode);
+    EXPECT_EQ("adiantum", entry->file_names_mode);
+
+    entry++;
+    EXPECT_EQ("none10", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ("", entry->file_contents_mode);
+    EXPECT_EQ("", entry->file_names_mode);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MaxCompStreams) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      max_comp_streams=blah
+source none1       swap   defaults      max_comp_streams=123456
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(2U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.max_comp_streams = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->max_comp_streams);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(123456, entry->max_comp_streams);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ReservedSize) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      reservedsize=blah
+source none1       swap   defaults      reservedsize=2
+source none2       swap   defaults      reservedsize=1K
+source none3       swap   defaults      reservedsize=2m
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(4U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.reserved_size = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->reserved_size);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(2, entry->reserved_size);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(1024, entry->reserved_size);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(2 * 1024 * 1024, entry->reserved_size);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_EraseBlk) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      eraseblk=blah
+source none1       swap   defaults      eraseblk=4000
+source none2       swap   defaults      eraseblk=5000
+source none3       swap   defaults      eraseblk=8192
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(4U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.erase_blk_size = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->erase_blk_size);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->erase_blk_size);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->erase_blk_size);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(8192, entry->erase_blk_size);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Logicalblk) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      logicalblk=blah
+source none1       swap   defaults      logicalblk=4000
+source none2       swap   defaults      logicalblk=5000
+source none3       swap   defaults      logicalblk=8192
+)fs";
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(4U, fstab.size());
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.logical_blk_size = true;
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->logical_blk_size);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->logical_blk_size);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(0, entry->logical_blk_size);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+    EXPECT_EQ(8192, entry->logical_blk_size);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Avb) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      avb=vbmeta_partition
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.avb = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("vbmeta_partition", entry->vbmeta_partition);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_KeyDirectory) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      keydirectory=/dir/key
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.key_directory = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/dir/key", entry->key_dir);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_SysfsPath) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      sysfs_path=/sys/device
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(1U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+
+    FstabEntry::FsMgrFlags flags = {0};
+    flags.sysfs = true;
+    EXPECT_EQ(flags.val, entry->fs_mgr_flags.val);
+
+    EXPECT_EQ("/sys/device", entry->sysfs_path);
+}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Zram) {
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    std::string fstab_contents = R"fs(
+source none0       swap   defaults      zram_loopback_path=/dev/path
+
+source none1       swap   defaults      zram_loopback_size=blah
+source none2       swap   defaults      zram_loopback_size=2
+source none3       swap   defaults      zram_loopback_size=1K
+source none4       swap   defaults      zram_loopback_size=2m
+
+source none5       swap   defaults      zram_backing_dev_path=/dev/path2
+
+)fs";
+
+    ASSERT_TRUE(android::base::WriteStringToFd(fstab_contents, tf.fd));
+
+    Fstab fstab;
+    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+    ASSERT_EQ(6U, fstab.size());
+
+    auto entry = fstab.begin();
+    EXPECT_EQ("none0", entry->mount_point);
+    EXPECT_EQ("/dev/path", entry->zram_loopback_path);
+    entry++;
+
+    EXPECT_EQ("none1", entry->mount_point);
+    EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
+    entry++;
+
+    EXPECT_EQ("none2", entry->mount_point);
+    EXPECT_EQ(2U, entry->zram_loopback_size);
+    entry++;
+
+    EXPECT_EQ("none3", entry->mount_point);
+    EXPECT_EQ(1024U, entry->zram_loopback_size);
+    entry++;
+
+    EXPECT_EQ("none4", entry->mount_point);
+    EXPECT_EQ(2U * 1024U * 1024U, entry->zram_loopback_size);
+    entry++;
+
+    EXPECT_EQ("none5", entry->mount_point);
+    EXPECT_EQ("/dev/path2", entry->zram_backing_dev_path);
 }
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 10b7550..a416825 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -35,11 +35,11 @@
 # APEX related namespaces.
 ###############################################################################
 
-additional.namespaces = runtime,conscrypt,media
+additional.namespaces = runtime,conscrypt,media,resolv
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
-namespace.default.links = runtime
-namespace.default.asan.links = runtime
+namespace.default.links = runtime,resolv
+namespace.default.asan.links = runtime,resolv
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
@@ -49,6 +49,8 @@
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
 
+namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -100,6 +102,22 @@
 namespace.conscrypt.link.default.shared_libs += libdl.so
 
 ###############################################################################
+# "resolv" APEX namespace
+#
+# This namespace is for libraries within the resolv APEX.
+###############################################################################
+namespace.resolv.isolated = true
+namespace.resolv.visible = true
+
+namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.links = default
+namespace.resolv.link.default.shared_libs  = libc.so
+namespace.resolv.link.default.shared_libs += libm.so
+namespace.resolv.link.default.shared_libs += libdl.so
+namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+
+###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only one default namespace is defined and it has no directories other than
 # /system/lib and /product/lib in the search paths. This is because linker
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 5c14d2a..d0e84df 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -28,7 +28,7 @@
 dir.postinstall = /postinstall
 
 [system]
-additional.namespaces = runtime,conscrypt,media,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
 
 ###############################################################################
 # "default" namespace
@@ -73,7 +73,6 @@
 namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.permitted.paths += /data
 namespace.default.permitted.paths += /mnt/expand
-namespace.default.permitted.paths += /apex/com.android.resolv/${LIB}
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
@@ -105,10 +104,9 @@
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.asan.permitted.paths += /mnt/expand
-namespace.default.asan.permitted.paths += /apex/com.android.resolv/${LIB}
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
-namespace.default.links = runtime
+namespace.default.links = runtime,resolv
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
@@ -118,6 +116,8 @@
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
 
+namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -169,6 +169,22 @@
 namespace.conscrypt.link.default.shared_libs += libdl.so
 
 ###############################################################################
+# "resolv" APEX namespace
+#
+# This namespace is for libraries within the resolv APEX.
+###############################################################################
+namespace.resolv.isolated = true
+namespace.resolv.visible = true
+
+namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.links = default
+namespace.resolv.link.default.shared_libs  = libc.so
+namespace.resolv.link.default.shared_libs += libm.so
+namespace.resolv.link.default.shared_libs += libdl.so
+namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+
+###############################################################################
 # "sphal" namespace
 #
 # SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 0371345..d2c0f2e 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -28,7 +28,7 @@
 dir.postinstall = /postinstall
 
 [system]
-additional.namespaces = runtime,conscrypt,media,sphal,vndk,rs
+additional.namespaces = runtime,conscrypt,media,resolv,sphal,vndk,rs
 
 ###############################################################################
 # "default" namespace
@@ -57,7 +57,7 @@
 
 # Keep in sync with the platform namespace in the com.android.runtime APEX
 # ld.config.txt.
-namespace.default.links = runtime
+namespace.default.links = runtime,resolv
 # Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
 # libart.
 namespace.default.visible = true
@@ -66,6 +66,8 @@
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
 
+namespace.default.link.resolv.shared_libs = libnetd_resolv.so
+
 ###############################################################################
 # "runtime" APEX namespace
 #
@@ -118,6 +120,22 @@
 namespace.conscrypt.link.default.shared_libs += libdl.so
 
 ###############################################################################
+# "resolv" APEX namespace
+#
+# This namespace is for libraries within the resolv APEX.
+###############################################################################
+namespace.resolv.isolated = true
+namespace.resolv.visible = true
+
+namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
+namespace.resolv.links = default
+namespace.resolv.link.default.shared_libs  = libc.so
+namespace.resolv.link.default.shared_libs += libm.so
+namespace.resolv.link.default.shared_libs += libdl.so
+namespace.resolv.link.default.shared_libs += libbinder_ndk.so
+
+###############################################################################
 # "sphal" namespace
 #
 # SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be