Merge "Adding libfs_avb host tests into presubmit"
diff --git a/.clang-format-2 b/.clang-format-2
deleted file mode 100644
index ede5d7e..0000000
--- a/.clang-format-2
+++ /dev/null
@@ -1,9 +0,0 @@
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-IndentWidth: 2
-PointerAlignment: Left
-TabWidth: 2
-UseTab: Never
diff --git a/.clang-format-2 b/.clang-format-2
new file mode 120000
index 0000000..7ab20d4
--- /dev/null
+++ b/.clang-format-2
@@ -0,0 +1 @@
+../../build/soong/scripts/system-clang-format-2
\ No newline at end of file
diff --git a/.clang-format-4 b/.clang-format-4
deleted file mode 100644
index 55773a2..0000000
--- a/.clang-format-4
+++ /dev/null
@@ -1,11 +0,0 @@
-BasedOnStyle: Google
-AccessModifierOffset: -2
-AllowShortFunctionsOnASingleLine: Inline
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-IndentWidth: 4
-ContinuationIndentWidth: 8
-PointerAlignment: Left
-TabWidth: 4
-UseTab: Never
diff --git a/.clang-format-4 b/.clang-format-4
new file mode 120000
index 0000000..ddcf5a2
--- /dev/null
+++ b/.clang-format-4
@@ -0,0 +1 @@
+../../build/soong/scripts/system-clang-format
\ No newline at end of file
diff --git a/Android.mk b/Android.mk
deleted file mode 100644
index 7c57258..0000000
--- a/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-#
-# Copyright (C) 2008 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.
-#
-LOCAL_PATH := $(my-dir)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f9c3b4a..bc5685b 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -7,6 +7,9 @@
       "name": "debuggerd_test"
     },
     {
+      "name": "fs_mgr_unit_test"
+    },
+    {
       "name": "init_tests"
     },
     {
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 06e4c50..a5b2f7b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1134,7 +1134,9 @@
         std::string host;
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
         std::string error;
-        if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
+        if (address.starts_with("vsock:")) {
+            serial = address;
+        } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
             SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
                                                            address.c_str(), error.c_str()));
             return true;
diff --git a/adb/adb.h b/adb/adb.h
index d79cd2d..9209997 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -139,7 +139,7 @@
 atransport* find_emulator_transport_by_console_port(int console_port);
 #endif
 
-int service_to_fd(std::string_view name, atransport* transport);
+unique_fd service_to_fd(std::string_view name, atransport* transport);
 #if !ADB_HOST
 unique_fd daemon_service_to_fd(std::string_view name, atransport* transport);
 #endif
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index be457a6..29909a5 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -75,41 +75,36 @@
 
 static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
     if (ev & FDE_READ) {
-        int fd = adb_socket_accept(_fd, nullptr, nullptr);
+        unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
         if (fd < 0) return;
 
         int rcv_buf_size = CHUNK_SIZE;
-        adb_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
+        adb_setsockopt(fd.get(), SOL_SOCKET, SO_RCVBUF, &rcv_buf_size, sizeof(rcv_buf_size));
 
-        asocket* s = create_local_socket(fd);
+        asocket* s = create_local_socket(std::move(fd));
         if (s) {
             connect_to_smartsocket(s);
             return;
         }
-
-        adb_close(fd);
     }
 }
 
 static void listener_event_func(int _fd, unsigned ev, void* _l)
 {
     alistener* listener = reinterpret_cast<alistener*>(_l);
-    asocket *s;
 
     if (ev & FDE_READ) {
-        int fd = adb_socket_accept(_fd, nullptr, nullptr);
+        unique_fd fd(adb_socket_accept(_fd, nullptr, nullptr));
         if (fd < 0) {
             return;
         }
 
-        s = create_local_socket(fd);
+        asocket* s = create_local_socket(std::move(fd));
         if (s) {
             s->transport = listener->transport;
             connect_to_remote(s, listener->connect_to);
             return;
         }
-
-        adb_close(fd);
     }
 }
 
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 8253487..a85ca8c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -53,8 +53,6 @@
 
 bool set_file_block_mode(int fd, bool block);
 
-int adb_close(int fd);
-
 // Given forward/reverse targets, returns true if they look sane. If an error is found, fills
 // |error| and returns false.
 // Currently this only checks "tcp:" targets. Additional checking could be added for other targets
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index bb09425..8518e17 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -147,17 +147,16 @@
 
 #if !defined(_WIN32)
 TEST(adb_utils, set_file_block_mode) {
-  int fd = adb_open("/dev/null", O_RDWR | O_APPEND);
-  ASSERT_GE(fd, 0);
-  int flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND)));
-  ASSERT_TRUE(set_file_block_mode(fd, false));
-  int new_flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(flags | O_NONBLOCK, new_flags);
-  ASSERT_TRUE(set_file_block_mode(fd, true));
-  new_flags = fcntl(fd, F_GETFL, 0);
-  ASSERT_EQ(flags, new_flags);
-  ASSERT_EQ(0, adb_close(fd));
+    unique_fd fd(adb_open("/dev/null", O_RDWR | O_APPEND));
+    ASSERT_GE(fd, 0);
+    int flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND)));
+    ASSERT_TRUE(set_file_block_mode(fd, false));
+    int new_flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(flags | O_NONBLOCK, new_flags);
+    ASSERT_TRUE(set_file_block_mode(fd, true));
+    new_flags = fcntl(fd, F_GETFL, 0);
+    ASSERT_EQ(flags, new_flags);
 }
 #endif
 
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 9a25d10..0a09d1e 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -100,13 +100,11 @@
 
     if (!SendProtocolString(fd, service)) {
         *error = perror_str("write failure during connection");
-        adb_close(fd);
         return -1;
     }
     D("Switch transport in progress");
 
     if (!adb_status(fd, error)) {
-        adb_close(fd);
         D("Switch transport failed: %s", error->c_str());
         return -1;
     }
@@ -194,7 +192,7 @@
 
 int adb_connect(const std::string& service, std::string* error) {
     // first query the adb server's version
-    int fd = _adb_connect("host:version", error);
+    unique_fd fd(_adb_connect("host:version", error));
 
     D("adb_connect: service %s", service.c_str());
     if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
@@ -224,12 +222,10 @@
         if (fd >= 0) {
             std::string version_string;
             if (!ReadProtocolString(fd, &version_string, error)) {
-                adb_close(fd);
                 return -1;
             }
 
             ReadOrderlyShutdown(fd);
-            adb_close(fd);
 
             if (sscanf(&version_string[0], "%04x", &version) != 1) {
                 *error = android::base::StringPrintf("cannot parse version string: %s",
@@ -258,52 +254,48 @@
         return 0;
     }
 
-    fd = _adb_connect(service, error);
+    fd.reset(_adb_connect(service, error));
     if (fd == -1) {
         D("_adb_connect error: %s", error->c_str());
     } else if(fd == -2) {
         fprintf(stderr, "* daemon still not running\n");
     }
-    D("adb_connect: return fd %d", fd);
+    D("adb_connect: return fd %d", fd.get());
 
-    return fd;
+    return fd.release();
 }
 
 
 bool adb_command(const std::string& service) {
     std::string error;
-    int fd = adb_connect(service, &error);
+    unique_fd fd(adb_connect(service, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return false;
     }
 
-    if (!adb_status(fd, &error)) {
+    if (!adb_status(fd.get(), &error)) {
         fprintf(stderr, "error: %s\n", error.c_str());
-        adb_close(fd);
         return false;
     }
 
-    ReadOrderlyShutdown(fd);
-    adb_close(fd);
+    ReadOrderlyShutdown(fd.get());
     return true;
 }
 
 bool adb_query(const std::string& service, std::string* result, std::string* error) {
     D("adb_query: %s", service.c_str());
-    int fd = adb_connect(service, error);
+    unique_fd fd(adb_connect(service, error));
     if (fd < 0) {
         return false;
     }
 
     result->clear();
-    if (!ReadProtocolString(fd, result, error)) {
-        adb_close(fd);
+    if (!ReadProtocolString(fd.get(), result, error)) {
         return false;
     }
 
-    ReadOrderlyShutdown(fd);
-    adb_close(fd);
+    ReadOrderlyShutdown(fd.get());
     return true;
 }
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e963e3d..f70b480 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -794,7 +794,7 @@
 
 static int adb_sideload_legacy(const char* filename, int in_fd, int size) {
     std::string error;
-    int out_fd = adb_connect(android::base::StringPrintf("sideload:%d", size), &error);
+    unique_fd out_fd(adb_connect(android::base::StringPrintf("sideload:%d", size), &error));
     if (out_fd < 0) {
         fprintf(stderr, "adb: pre-KitKat sideload connection failed: %s\n", error.c_str());
         return -1;
@@ -809,14 +809,12 @@
         unsigned xfer = (size > CHUNK_SIZE) ? CHUNK_SIZE : size;
         if (!ReadFdExactly(in_fd, buf, xfer)) {
             fprintf(stderr, "adb: failed to read data from %s: %s\n", filename, strerror(errno));
-            adb_close(out_fd);
             return -1;
         }
         if (!WriteFdExactly(out_fd, buf, xfer)) {
             std::string error;
             adb_status(out_fd, &error);
             fprintf(stderr, "adb: failed to write data: %s\n", error.c_str());
-            adb_close(out_fd);
             return -1;
         }
         size -= xfer;
@@ -827,11 +825,9 @@
 
     if (!adb_status(out_fd, &error)) {
         fprintf(stderr, "adb: error response: %s\n", error.c_str());
-        adb_close(out_fd);
         return -1;
     }
 
-    adb_close(out_fd);
     return 0;
 }
 
@@ -1091,7 +1087,7 @@
 
 int send_shell_command(const std::string& command, bool disable_shell_protocol,
                        StandardStreamsCallbackInterface* callback) {
-    int fd;
+    unique_fd fd;
     bool use_shell_protocol = false;
 
     while (true) {
@@ -1114,7 +1110,7 @@
             std::string error;
             std::string service_string = ShellServiceString(use_shell_protocol, "", command);
 
-            fd = adb_connect(service_string, &error);
+            fd.reset(adb_connect(service_string, &error));
             if (fd >= 0) {
                 break;
             }
@@ -1126,13 +1122,7 @@
         }
     }
 
-    int exit_code = read_and_dump(fd, use_shell_protocol, callback);
-
-    if (adb_close(fd) < 0) {
-        PLOG(ERROR) << "failure closing FD " << fd;
-    }
-
-    return exit_code;
+    return read_and_dump(fd.get(), use_shell_protocol, callback);
 }
 
 static int logcat(int argc, const char** argv) {
@@ -1196,7 +1186,7 @@
     if (argc < 2) error_exit("backup either needs a list of packages or -all/-shared");
 
     adb_unlink(filename);
-    int outFd = adb_creat(filename, 0640);
+    unique_fd outFd(adb_creat(filename, 0640));
     if (outFd < 0) {
         fprintf(stderr, "adb: backup unable to create file '%s': %s\n", filename, strerror(errno));
         return EXIT_FAILURE;
@@ -1211,20 +1201,16 @@
 
     D("backup. filename=%s cmd=%s", filename, cmd.c_str());
     std::string error;
-    int fd = adb_connect(cmd, &error);
+    unique_fd fd(adb_connect(cmd, &error));
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
-        adb_close(outFd);
         return EXIT_FAILURE;
     }
 
     fprintf(stdout, "Now unlock your device and confirm the backup operation...\n");
     fflush(stdout);
 
-    copy_to_file(fd, outFd);
-
-    adb_close(fd);
-    adb_close(outFd);
+    copy_to_file(fd.get(), outFd.get());
     return EXIT_SUCCESS;
 }
 
@@ -1232,33 +1218,29 @@
     if (argc != 2) error_exit("restore requires an argument");
 
     const char* filename = argv[1];
-    int tarFd = adb_open(filename, O_RDONLY);
+    unique_fd tarFd(adb_open(filename, O_RDONLY));
     if (tarFd < 0) {
         fprintf(stderr, "adb: unable to open file %s: %s\n", filename, strerror(errno));
         return -1;
     }
 
     std::string error;
-    int fd = adb_connect("restore:", &error);
+    unique_fd fd(adb_connect("restore:", &error));
     if (fd < 0) {
         fprintf(stderr, "adb: unable to connect for restore: %s\n", error.c_str());
-        adb_close(tarFd);
         return -1;
     }
 
     fprintf(stdout, "Now unlock your device and confirm the restore operation.\n");
     fflush(stdout);
 
-    copy_to_file(tarFd, fd);
+    copy_to_file(tarFd.get(), fd.get());
 
     // Provide an in-band EOD marker in case the archive file is malformed
-    write_zeros(512*2, fd);
+    write_zeros(512 * 2, fd);
 
     // Wait until the other side finishes, or it'll get sent SIGHUP.
-    copy_to_file(fd, STDOUT_FILENO);
-
-    adb_close(fd);
-    adb_close(tarFd);
+    copy_to_file(fd.get(), STDOUT_FILENO);
     return 0;
 }
 
@@ -1298,19 +1280,18 @@
 
 static int adb_connect_command(const std::string& command) {
     std::string error;
-    int fd = adb_connect(command, &error);
+    unique_fd fd(adb_connect(command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
     }
     read_and_dump(fd);
-    adb_close(fd);
     return 0;
 }
 
 static int adb_connect_command_bidirectional(const std::string& command) {
     std::string error;
-    int fd = adb_connect(command, &error);
+    unique_fd fd(adb_connect(command, &error));
     if (fd < 0) {
         fprintf(stderr, "error: %s\n", error.c_str());
         return 1;
@@ -1336,11 +1317,10 @@
         }
     };
 
-    std::thread read(forward, fd, STDOUT_FILENO, true);
-    std::thread write(forward, STDIN_FILENO, fd, false);
+    std::thread read(forward, fd.get(), STDOUT_FILENO, true);
+    std::thread write(forward, STDIN_FILENO, fd.get(), false);
     read.join();
     write.join();
-    adb_close(fd);
     return 0;
 }
 
@@ -1599,19 +1579,17 @@
         }
 
         std::string error;
-        int fd = adb_connect(cmd, &error);
+        unique_fd fd(adb_connect(cmd, &error));
         if (fd < 0) {
             fprintf(stderr, "error: %s\n", error.c_str());
             return -1;
         }
 
         if (exec_in) {
-            copy_to_file(STDIN_FILENO, fd);
+            copy_to_file(STDIN_FILENO, fd.get());
         } else {
-            copy_to_file(fd, STDOUT_FILENO);
+            copy_to_file(fd.get(), STDOUT_FILENO);
         }
-
-        adb_close(fd);
         return 0;
     } else if (!strcmp(argv[0], "kill-server")) {
         return adb_kill_server() ? 0 : 1;
@@ -1706,9 +1684,8 @@
             error_exit("error: %s", error_message.c_str());
         }
 
-        int fd = adb_connect(cmd, &error_message);
-        if (fd < 0 || !adb_status(fd, &error_message)) {
-            adb_close(fd);
+        unique_fd fd(adb_connect(cmd, &error_message));
+        if (fd < 0 || !adb_status(fd.get(), &error_message)) {
             error_exit("error: %s", error_message.c_str());
         }
 
diff --git a/adb/client/console.cpp b/adb/client/console.cpp
index 4e8a3f8..1dbb6e2 100644
--- a/adb/client/console.cpp
+++ b/adb/client/console.cpp
@@ -108,7 +108,7 @@
 }
 
 int adb_send_emulator_command(int argc, const char** argv, const char* serial) {
-    int fd = connect_to_console(serial);
+    unique_fd fd(connect_to_console(serial));
     if (fd == -1) {
         return 1;
     }
@@ -125,7 +125,6 @@
     if (!WriteFdExactly(fd, commands)) {
         fprintf(stderr, "error: cannot write to emulator: %s\n",
                 strerror(errno));
-        adb_close(fd);
         return 1;
     }
 
@@ -178,7 +177,5 @@
     }
 
     printf("%s", emulator_output.c_str() + found);
-    adb_close(fd);
-
     return 0;
 }
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index f0f9a80..b8827ef 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -207,11 +207,10 @@
 
         std::string error;
         if (!adb_get_feature_set(&features_, &error)) {
-            fd = -1;
             Error("failed to get feature set: %s", error.c_str());
         } else {
             have_stat_v2_ = CanUseFeature(features_, kFeatureStat2);
-            fd = adb_connect("sync:", &error);
+            fd.reset(adb_connect("sync:", &error));
             if (fd < 0) {
                 Error("connect failed: %s", error.c_str());
             }
@@ -230,7 +229,6 @@
             // case, this will wait for the server to do orderly shutdown.
             ReadOrderlyShutdown(fd);
         }
-        adb_close(fd);
 
         line_printer_.KeepInfoLine();
     }
@@ -240,7 +238,7 @@
     bool IsValid() { return fd >= 0; }
 
     bool ReceivedError(const char* from, const char* to) {
-        adb_pollfd pfd = {.fd = fd, .events = POLLIN};
+        adb_pollfd pfd = {.fd = fd.get(), .events = POLLIN};
         int rc = adb_poll(&pfd, 1, 0);
         if (rc < 0) {
             Error("failed to poll: %s", strerror(errno));
@@ -324,7 +322,7 @@
 
         memset(st, 0, sizeof(*st));
         if (have_stat_v2_) {
-            if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
+            if (!ReadFdExactly(fd.get(), &msg.stat_v2, sizeof(msg.stat_v2))) {
                 PLOG(FATAL) << "protocol fault: failed to read stat response";
             }
 
@@ -350,7 +348,7 @@
             st->st_ctime = msg.stat_v2.ctime;
             return true;
         } else {
-            if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
+            if (!ReadFdExactly(fd.get(), &msg.stat_v1, sizeof(msg.stat_v1))) {
                 PLOG(FATAL) << "protocol fault: failed to read stat response";
             }
 
@@ -437,7 +435,7 @@
         uint64_t total_size = st.st_size;
         uint64_t bytes_copied = 0;
 
-        int lfd = adb_open(lpath, O_RDONLY);
+        unique_fd lfd(adb_open(lpath, O_RDONLY));
         if (lfd < 0) {
             Error("opening '%s' locally failed: %s", lpath, strerror(errno));
             return false;
@@ -449,7 +447,6 @@
             int bytes_read = adb_read(lfd, sbuf.data, max - sizeof(SyncRequest));
             if (bytes_read == -1) {
                 Error("reading '%s' locally failed: %s", lpath, strerror(errno));
-                adb_close(lfd);
                 return false;
             } else if (bytes_read == 0) {
                 break;
@@ -469,8 +466,6 @@
             ReportProgress(rpath, bytes_copied, total_size);
         }
 
-        adb_close(lfd);
-
         syncmsg msg;
         msg.data.id = ID_DONE;
         msg.data.size = mtime;
@@ -576,7 +571,7 @@
     }
 
     // TODO: add a char[max] buffer here, to replace syncsendbuf...
-    int fd;
+    unique_fd fd;
     size_t max;
 
   private:
@@ -740,7 +735,7 @@
     if (!sc.SendRequest(ID_RECV, rpath)) return false;
 
     adb_unlink(lpath);
-    int lfd = adb_creat(lpath, 0644);
+    unique_fd lfd(adb_creat(lpath, 0644));
     if (lfd < 0) {
         sc.Error("cannot create '%s': %s", lpath, strerror(errno));
         return false;
@@ -750,7 +745,6 @@
     while (true) {
         syncmsg msg;
         if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
@@ -758,7 +752,6 @@
         if (msg.data.id == ID_DONE) break;
 
         if (msg.data.id != ID_DATA) {
-            adb_close(lfd);
             adb_unlink(lpath);
             sc.ReportCopyFailure(rpath, lpath, msg);
             return false;
@@ -766,21 +759,18 @@
 
         if (msg.data.size > sc.max) {
             sc.Error("msg.data.size too large: %u (max %zu)", msg.data.size, sc.max);
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
 
         char buffer[SYNC_DATA_MAX];
         if (!ReadFdExactly(sc.fd, buffer, msg.data.size)) {
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
 
         if (!WriteFdExactly(lfd, buffer, msg.data.size)) {
             sc.Error("cannot write '%s': %s", lpath, strerror(errno));
-            adb_close(lfd);
             adb_unlink(lpath);
             return false;
         }
@@ -792,7 +782,6 @@
     }
 
     sc.RecordFilesTransferred(1);
-    adb_close(lfd);
     return true;
 }
 
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 62c18c5..56b5cd8 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -232,7 +232,7 @@
 
     __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
 
-    int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+    unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
 
     if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) <
         0) {
@@ -244,16 +244,16 @@
             SendSyncFailErrno(s, "secure_mkdirs failed");
             goto fail;
         }
-        fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+        fd.reset(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
     }
     if (fd < 0 && errno == EEXIST) {
-        fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
+        fd.reset(adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode));
     }
     if (fd < 0) {
         SendSyncFailErrno(s, "couldn't create file");
         goto fail;
     } else {
-        if (fchown(fd, uid, gid) == -1) {
+        if (fchown(fd.get(), uid, gid) == -1) {
             SendSyncFailErrno(s, "fchown failed");
             goto fail;
         }
@@ -266,7 +266,7 @@
         // fchown clears the setuid bit - restore it if present.
         // Ignore the result of calling fchmod. It's not supported
         // by all filesystems, so we don't check for success. b/12441485
-        fchmod(fd, mode);
+        fchmod(fd.get(), mode);
     }
 
     while (true) {
@@ -288,14 +288,12 @@
 
         if (!ReadFdExactly(s, &buffer[0], msg.data.size)) goto abort;
 
-        if (!WriteFdExactly(fd, &buffer[0], msg.data.size)) {
+        if (!WriteFdExactly(fd.get(), &buffer[0], msg.data.size)) {
             SendSyncFailErrno(s, "write failed");
             goto fail;
         }
     }
 
-    adb_close(fd);
-
     if (!update_capabilities(path, capabilities)) {
         SendSyncFailErrno(s, "update_capabilities failed");
         goto fail;
@@ -340,7 +338,6 @@
     }
 
 abort:
-    if (fd >= 0) adb_close(fd);
     if (do_unlink) adb_unlink(path);
     return false;
 }
@@ -445,35 +442,31 @@
 static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
     __android_log_security_bswrite(SEC_TAG_ADB_RECV_FILE, path);
 
-    int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
+    unique_fd fd(adb_open(path, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         SendSyncFailErrno(s, "open failed");
         return false;
     }
 
-    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
+    if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
         D("[ Failed to fadvise: %d ]", errno);
     }
 
     syncmsg msg;
     msg.data.id = ID_DATA;
     while (true) {
-        int r = adb_read(fd, &buffer[0], buffer.size() - sizeof(msg.data));
+        int r = adb_read(fd.get(), &buffer[0], buffer.size() - sizeof(msg.data));
         if (r <= 0) {
             if (r == 0) break;
             SendSyncFailErrno(s, "read failed");
-            adb_close(fd);
             return false;
         }
         msg.data.size = r;
         if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
-            adb_close(fd);
             return false;
         }
     }
 
-    adb_close(fd);
-
     msg.data.id = ID_DONE;
     msg.data.size = 0;
     return WriteFdExactly(s, &msg.data, sizeof(msg.data));
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index f02cc13..032ee42 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -303,7 +303,6 @@
 static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
     sockaddr_un addr;
     socklen_t addrlen;
-    int s;
     int maxpath = sizeof(addr.sun_path);
     int pathlen = socknamelen;
 
@@ -316,7 +315,7 @@
     addr.sun_family = AF_UNIX;
     memcpy(addr.sun_path, sockname, socknamelen);
 
-    s = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+    unique_fd s(socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0));
     if (s < 0) {
         D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
         return -1;
@@ -326,22 +325,18 @@
 
     if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
         D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
-        adb_close(s);
         return -1;
     }
 
     if (listen(s, 4) < 0) {
         D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
-        adb_close(s);
         return -1;
     }
 
-    control->listen_socket = s;
-
-    control->fde = fdevent_create(s, jdwp_control_event, control);
+    control->listen_socket = s.release();
+    control->fde = fdevent_create(control->listen_socket, jdwp_control_event, control);
     if (control->fde == nullptr) {
         D("could not create fdevent for jdwp control socket");
-        adb_close(s);
         return -1;
     }
 
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 3c9dd04..b26c691 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -75,16 +75,20 @@
 
 // Returns the device used to mount a directory in the fstab.
 static std::string find_fstab_mount(const char* dir) {
-    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
-                                                               fs_mgr_free_fstab);
-    struct fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), dir);
-    if (!rec) {
+    Fstab fstab;
+    if (!ReadDefaultFstab(&fstab)) {
         return "";
     }
-    if (fs_mgr_is_logical(rec)) {
-        fs_mgr_update_logical_partition(rec);
+
+    auto entry = std::find_if(fstab.begin(), fstab.end(),
+                              [&dir](const auto& entry) { return entry.mount_point == dir; });
+    if (entry == fstab.end()) {
+        return "";
     }
-    return rec->blk_device;
+    if (entry->fs_mgr_flags.logical) {
+        fs_mgr_update_logical_partition(&(*entry));
+    }
+    return entry->blk_device;
 }
 
 // The proc entry for / is full of lies, so check fstab instead.
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 3676de5..f5c28c6 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -41,8 +41,6 @@
 
 #include "fec/io.h"
 
-struct fstab *fstab;
-
 #ifdef ALLOW_ADBD_DISABLE_VERITY
 static const bool kAllowDisableVerity = true;
 #else
@@ -213,18 +211,18 @@
         // Not using AVB - assume VB1.0.
 
         // read all fstab entries at once from all sources
-        if (!fstab) fstab = fs_mgr_read_fstab_default();
-        if (!fstab) {
+        Fstab fstab;
+        if (!ReadDefaultFstab(&fstab)) {
             WriteFdExactly(fd.get(), "Failed to read fstab\n");
             suggest_run_adb_root(fd.get());
             return;
         }
 
         // Loop through entries looking for ones that verity manages.
-        for (int i = 0; i < fstab->num_entries; i++) {
-            if (fs_mgr_is_verified(&fstab->recs[i])) {
-                if (set_verity_enabled_state(fd.get(), fstab->recs[i].blk_device,
-                                             fstab->recs[i].mount_point, enable)) {
+        for (const auto& entry : fstab) {
+            if (entry.fs_mgr_flags.verify) {
+                if (set_verity_enabled_state(fd.get(), entry.blk_device.c_str(),
+                                             entry.mount_point.c_str(), enable)) {
                     any_changed = true;
                 }
             }
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
index 8ad2572..e996c17 100644
--- a/adb/daemon/transport_qemu.cpp
+++ b/adb/daemon/transport_qemu.cpp
@@ -78,7 +78,7 @@
         /* This could be an older version of the emulator, that doesn't
          * implement adb QEMUD service. Fall back to the old TCP way. */
         D("adb service is not available. Falling back to TCP socket.");
-        std::thread(server_socket_thread, port).detach();
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
         return;
     }
 
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index 8d853c3..24bce59 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -21,6 +21,7 @@
 #include <thread>
 
 #include "adb_io.h"
+#include "adb_unique_fd.h"
 #include "socket.h"
 #include "sysdeps.h"
 #include "sysdeps/chrono.h"
@@ -45,7 +46,7 @@
 
 class FdeventTest : public ::testing::Test {
   protected:
-    int dummy = -1;
+    unique_fd dummy;
 
     static void SetUpTestCase() {
 #if !defined(_WIN32)
@@ -65,12 +66,12 @@
             FAIL() << "failed to create socketpair: " << strerror(errno);
         }
 
-        asocket* dummy_socket = create_local_socket(dummy_fds[1]);
+        asocket* dummy_socket = create_local_socket(unique_fd(dummy_fds[1]));
         if (!dummy_socket) {
             FAIL() << "failed to create local socket: " << strerror(errno);
         }
         dummy_socket->ready(dummy_socket);
-        dummy = dummy_fds[0];
+        dummy.reset(dummy_fds[0]);
 
         thread_ = std::thread([]() { fdevent_loop(); });
         WaitForFdeventLoop();
@@ -85,7 +86,7 @@
         fdevent_terminate_loop();
         ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
         thread_.join();
-        ASSERT_EQ(0, adb_close(dummy));
+        dummy.reset();
     }
 
     std::thread thread_;
diff --git a/adb/services.cpp b/adb/services.cpp
index 73fed09..0061f0e 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -71,7 +71,7 @@
     return unique_fd(s[0]);
 }
 
-int service_to_fd(std::string_view name, atransport* transport) {
+unique_fd service_to_fd(std::string_view name, atransport* transport) {
     unique_fd ret;
 
     if (is_socket_spec(name)) {
@@ -86,9 +86,9 @@
     }
 
     if (ret >= 0) {
-        close_on_exec(ret);
+        close_on_exec(ret.get());
     }
-    return ret.release();
+    return ret;
 }
 
 #if ADB_HOST
@@ -99,9 +99,7 @@
     ConnectionState state;
 };
 
-static void wait_for_state(int fd, void* data) {
-    std::unique_ptr<state_info> sinfo(reinterpret_cast<state_info*>(data));
-
+static void wait_for_state(int fd, state_info* sinfo) {
     D("wait_for_state %d", sinfo->state);
 
     while (true) {
@@ -197,7 +195,7 @@
     } else if (android::base::StartsWith(name, "wait-for-")) {
         name += strlen("wait-for-");
 
-        std::unique_ptr<state_info> sinfo = std::make_unique<state_info>();
+        std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
         if (sinfo == nullptr) {
             fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
             return nullptr;
@@ -233,19 +231,15 @@
             return nullptr;
         }
 
-        int fd = create_service_thread(
-                         "wait", std::bind(wait_for_state, std::placeholders::_1, sinfo.get()))
-                         .release();
-        if (fd != -1) {
-            sinfo.release();
-        }
-        return create_local_socket(fd);
+        unique_fd fd = create_service_thread("wait", [sinfo](int fd) {
+            wait_for_state(fd, sinfo.get());
+        });
+        return create_local_socket(std::move(fd));
     } else if (!strncmp(name, "connect:", 8)) {
         std::string host(name + strlen("connect:"));
-        int fd = create_service_thread("connect",
-                                       std::bind(connect_service, std::placeholders::_1, host))
-                         .release();
-        return create_local_socket(fd);
+        unique_fd fd = create_service_thread(
+                "connect", std::bind(connect_service, std::placeholders::_1, host));
+        return create_local_socket(std::move(fd));
     }
     return nullptr;
 }
diff --git a/adb/socket.h b/adb/socket.h
index e7df991..b8c559a 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -23,6 +23,7 @@
 #include <memory>
 #include <string>
 
+#include "adb_unique_fd.h"
 #include "fdevent.h"
 #include "types.h"
 
@@ -102,7 +103,7 @@
 void remove_socket(asocket *s);
 void close_all_sockets(atransport *t);
 
-asocket *create_local_socket(int fd);
+asocket* create_local_socket(unique_fd fd);
 asocket* create_local_service_socket(std::string_view destination, atransport* transport);
 
 asocket *create_remote_socket(unsigned id, atransport *t);
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index cc67b6b..de4fff9 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -46,6 +46,11 @@
 #define ADB_WINDOWS 0
 #endif
 
+#if ADB_LINUX
+#include <sys/socket.h>
+#include "sysdeps/vm_sockets.h"
+#endif
+
 // Not static because it is used in commandline.c.
 int gListenAll = 0;
 
@@ -174,6 +179,62 @@
             return true;
         }
         return false;
+    } else if (address.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(address);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        unsigned int port_value = port ? *port : 0;
+        if (fragments.size() != 2 && fragments.size() != 3) {
+            *error = android::base::StringPrintf("expected vsock:cid or vsock:port:cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        unsigned int cid = 0;
+        if (!android::base::ParseUint(fragments[1], &cid)) {
+            *error = android::base::StringPrintf("could not parse vsock cid in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (fragments.size() == 3 && !android::base::ParseUint(fragments[2], &port_value)) {
+            *error = android::base::StringPrintf("could not parse vsock port in '%s'",
+                                                 spec_str.c_str());
+            errno = EINVAL;
+            return false;
+        }
+        if (port_value == 0) {
+            *error = android::base::StringPrintf("vsock port was not provided.");
+            errno = EINVAL;
+            return false;
+        }
+        fd->reset(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (fd->get() == -1) {
+            *error = "could not open vsock socket";
+            return false;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port_value;
+        addr.svm_cid = cid;
+        if (serial) {
+            *serial = android::base::StringPrintf("vsock:%u:%d", cid, port_value);
+        }
+        if (connect(fd->get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not connect to vsock address '%s'",
+                                                 spec_str.c_str());
+            errno = error_num;
+            return false;
+        }
+        if (port) {
+            *port = port_value;
+        }
+        return true;
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return false;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
@@ -187,6 +248,9 @@
 
             fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
                                            SOCK_STREAM, error));
+            if (serial) {
+                *serial = address;
+            }
             return true;
         }
     }
@@ -196,7 +260,7 @@
     return false;
 }
 
-int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) {
+int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_port) {
     if (spec.starts_with("tcp:")) {
         std::string hostname;
         int port;
@@ -215,10 +279,59 @@
             return -1;
         }
 
-        if (result >= 0 && port == 0 && resolved_tcp_port) {
-            *resolved_tcp_port = adb_socket_get_local_port(result);
+        if (result >= 0 && resolved_port) {
+            *resolved_port = adb_socket_get_local_port(result);
         }
         return result;
+    } else if (spec.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(spec);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        if (fragments.size() != 2) {
+            *error = "given vsock server socket string was invalid";
+            return -1;
+        }
+        int port;
+        if (!android::base::ParseInt(fragments[1], &port)) {
+            *error = "could not parse vsock port";
+            errno = EINVAL;
+            return -1;
+        } else if (port < 0) {
+            *error = "vsock port was negative.";
+            errno = EINVAL;
+            return -1;
+        }
+        unique_fd serverfd(socket(AF_VSOCK, SOCK_STREAM, 0));
+        if (serverfd == -1) {
+            int error_num = errno;
+            *error = android::base::StringPrintf("could not create vsock server: '%s'",
+                                                 strerror(error_num));
+            errno = error_num;
+            return -1;
+        }
+        sockaddr_vm addr{};
+        addr.svm_family = AF_VSOCK;
+        addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port;
+        addr.svm_cid = VMADDR_CID_ANY;
+        socklen_t addr_len = sizeof(addr);
+        if (bind(serverfd, reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
+            return -1;
+        }
+        if (listen(serverfd, 4)) {
+            return -1;
+        }
+        if (serverfd >= 0 && resolved_port) {
+            if (getsockname(serverfd, reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
+                *resolved_port = addr.svm_port;
+            } else {
+                return -1;
+            }
+        }
+        return serverfd.release();
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return -1;
+#endif  // ADB_LINUX
     }
 
     for (const auto& it : kLocalSocketTypes) {
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 80f9430..7908f82 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -58,7 +58,7 @@
     intermediates.resize(INTERMEDIATE_COUNT);
     ASSERT_EQ(0, adb_socketpair(first)) << strerror(errno);
     ASSERT_EQ(0, adb_socketpair(last)) << strerror(errno);
-    asocket* prev_tail = create_local_socket(first[1]);
+    asocket* prev_tail = create_local_socket(unique_fd(first[1]));
     ASSERT_NE(nullptr, prev_tail);
 
     auto connect = [](asocket* tail, asocket* head) {
@@ -70,17 +70,17 @@
     for (auto& intermediate : intermediates) {
         ASSERT_EQ(0, adb_socketpair(intermediate.data())) << strerror(errno);
 
-        asocket* head = create_local_socket(intermediate[0]);
+        asocket* head = create_local_socket(unique_fd(intermediate[0]));
         ASSERT_NE(nullptr, head);
 
-        asocket* tail = create_local_socket(intermediate[1]);
+        asocket* tail = create_local_socket(unique_fd(intermediate[1]));
         ASSERT_NE(nullptr, tail);
 
         connect(prev_tail, head);
         prev_tail = tail;
     }
 
-    asocket* end = create_local_socket(last[0]);
+    asocket* end = create_local_socket(unique_fd(last[0]));
     ASSERT_NE(nullptr, end);
     connect(prev_tail, end);
 
@@ -104,14 +104,14 @@
 }
 
 struct CloseWithPacketArg {
-    int socket_fd;
+    unique_fd socket_fd;
     size_t bytes_written;
-    int cause_close_fd;
+    unique_fd cause_close_fd;
 };
 
 static void CreateCloser(CloseWithPacketArg* arg) {
     fdevent_run_on_main_thread([arg]() {
-        asocket* s = create_local_socket(arg->socket_fd);
+        asocket* s = create_local_socket(std::move(arg->socket_fd));
         ASSERT_TRUE(s != nullptr);
         arg->bytes_written = 0;
 
@@ -135,7 +135,7 @@
         }
         ASSERT_TRUE(socket_filled);
 
-        asocket* cause_close_s = create_local_socket(arg->cause_close_fd);
+        asocket* cause_close_s = create_local_socket(std::move(arg->cause_close_fd));
         ASSERT_TRUE(cause_close_s != nullptr);
         cause_close_s->peer = s;
         s->peer = cause_close_s;
@@ -154,8 +154,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -178,8 +178,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -211,8 +211,8 @@
     int cause_close_fd[2];
     ASSERT_EQ(0, adb_socketpair(cause_close_fd));
     CloseWithPacketArg arg;
-    arg.socket_fd = socket_fd[1];
-    arg.cause_close_fd = cause_close_fd[1];
+    arg.socket_fd.reset(socket_fd[1]);
+    arg.cause_close_fd.reset(cause_close_fd[1]);
 
     PrepareThread();
     CreateCloser(&arg);
@@ -233,8 +233,8 @@
     ASSERT_EQ(0, adb_socketpair(head_fd));
     ASSERT_EQ(0, adb_socketpair(tail_fd));
 
-    asocket* head = create_local_socket(head_fd[1]);
-    asocket* tail = create_local_socket(tail_fd[1]);
+    asocket* head = create_local_socket(unique_fd(head_fd[1]));
+    asocket* tail = create_local_socket(unique_fd(tail_fd[1]));
 
     head->peer = tail;
     head->ready(head);
@@ -287,7 +287,7 @@
     PrepareThread();
 
     fdevent_run_on_main_thread([accept_fd]() {
-        asocket* s = create_local_socket(accept_fd);
+        asocket* s = create_local_socket(unique_fd(accept_fd));
         ASSERT_TRUE(s != nullptr);
     });
 
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 47ae883..f7c39f0 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -333,7 +333,8 @@
     }
 }
 
-asocket* create_local_socket(int fd) {
+asocket* create_local_socket(unique_fd ufd) {
+    int fd = ufd.release();
     asocket* s = new asocket();
     s->fd = fd;
     s->enqueue = local_socket_enqueue;
@@ -353,13 +354,14 @@
         return s;
     }
 #endif
-    int fd = service_to_fd(name, transport);
+    unique_fd fd = service_to_fd(name, transport);
     if (fd < 0) {
         return nullptr;
     }
 
-    asocket* s = create_local_socket(fd);
-    LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd;
+    int fd_value = fd.get();
+    asocket* s = create_local_socket(std::move(fd));
+    LOG(VERBOSE) << "LS(" << s->id << "): bound to '" << name << "' via " << fd_value;
 
 #if !ADB_HOST
     if ((name.starts_with("root:") && getuid() != 0 && __android_log_is_debuggable()) ||
@@ -608,6 +610,14 @@
             return false;
         }
     }
+    if (command.starts_with("vsock:")) {
+        // vsock serials are vsock:cid:port, which have an extra colon compared to tcp.
+        size_t next_colon = command.find(':');
+        if (next_colon == std::string::npos) {
+            return false;
+        }
+        consume(next_colon + 1);
+    }
 
     bool found_address = false;
     if (command[0] == '[') {
diff --git a/adb/sysdeps/vm_sockets.h b/adb/sysdeps/vm_sockets.h
new file mode 100644
index 0000000..75c5f44
--- /dev/null
+++ b/adb/sysdeps/vm_sockets.h
@@ -0,0 +1,49 @@
+#if __BIONIC__
+#include <linux/vm_sockets.h>
+#else
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_VM_SOCKETS_H
+#define _UAPI_VM_SOCKETS_H
+#include <linux/socket.h>
+#define SO_VM_SOCKETS_BUFFER_SIZE 0
+#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1
+#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2
+#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3
+#define SO_VM_SOCKETS_TRUSTED 5
+#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6
+#define SO_VM_SOCKETS_NONBLOCK_TXRX 7
+#define VMADDR_CID_ANY -1U
+#define VMADDR_PORT_ANY -1U
+#define VMADDR_CID_HYPERVISOR 0
+#define VMADDR_CID_RESERVED 1
+#define VMADDR_CID_HOST 2
+#define VM_SOCKETS_INVALID_VERSION -1U
+#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24)
+#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16)
+#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF))
+struct sockaddr_vm {
+    __kernel_sa_family_t svm_family;
+    unsigned short svm_reserved1;
+    unsigned int svm_port;
+    unsigned int svm_cid;
+    unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) -
+                           sizeof(unsigned int) - sizeof(unsigned int)];
+};
+#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+#endif
+#endif
diff --git a/adb/transport.h b/adb/transport.h
index 3baeb1c..71e4857 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -28,6 +28,7 @@
 #include <memory>
 #include <mutex>
 #include <string>
+#include <string_view>
 #include <thread>
 #include <unordered_set>
 
@@ -400,7 +401,7 @@
 asocket* create_device_tracker(bool long_output);
 
 #if !ADB_HOST
-void server_socket_thread(int port);
+void server_socket_thread(std::string_view spec);
 
 #if defined(__ANDROID__)
 void qemu_socket_thread(int port);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 8885db4..c254d1d 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 
 #include <condition_variable>
+#include <functional>
 #include <memory>
 #include <mutex>
 #include <thread>
@@ -74,14 +75,15 @@
     unique_fd fd;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
     std::string serial;
-    if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
+    std::string prefix_addr = address.starts_with("vsock:") ? address : "tcp:" + address;
+    if (socket_spec_connect(&fd, prefix_addr, &port, &serial, response)) {
         close_on_exec(fd);
         if (!set_tcp_keepalive(fd, 1)) {
             D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
         }
         return std::make_tuple(std::move(fd), port, serial);
     }
-    return std::make_tuple(unique_fd(), 0, "");
+    return std::make_tuple(unique_fd(), 0, serial);
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -95,6 +97,9 @@
     int port;
     std::string serial;
     std::tie(fd, port, serial) = tcp_connect(address, response);
+    if (fd.get() == -1) {
+        return;
+    }
     auto reconnect = [address](atransport* t) {
         std::string response;
         unique_fd fd;
@@ -231,16 +236,20 @@
 
 #else  // !ADB_HOST
 
-void server_socket_thread(int port) {
+void server_socket_thread(std::string_view spec) {
     unique_fd serverfd;
 
     adb_thread_setname("server socket");
     D("transport: server_socket_thread() starting");
+    int port;
     while (serverfd == -1) {
-        std::string spec = android::base::StringPrintf("tcp:%d", port);
         std::string error;
-        serverfd.reset(socket_spec_listen(spec, &error));
-        if (serverfd < 0) {
+        errno = 0;
+        serverfd.reset(socket_spec_listen(spec, &error, &port));
+        if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
+            D("unrecoverable error: '%s'", error.c_str());
+            return;
+        } else if (serverfd < 0) {
             D("server: cannot bind socket yet: %s", error.c_str());
             std::this_thread::sleep_for(1s);
             continue;
@@ -249,7 +258,8 @@
     }
 
     while (true) {
-        D("server: trying to get new connection from %d", port);
+        std::string spec_str{spec};
+        D("server: trying to get new connection from %s", spec_str.c_str());
         unique_fd fd(adb_socket_accept(serverfd, nullptr, nullptr));
         if (fd >= 0) {
             D("server: new connection on fd %d", fd.get());
@@ -266,25 +276,25 @@
 #endif
 
 void local_init(int port) {
-    void (*func)(int);
-    const char* debug_name = "";
-
 #if ADB_HOST
-    func = client_socket_thread;
-    debug_name = "client";
+    D("transport: local client init");
+    std::thread(client_socket_thread, port).detach();
 #elif !defined(__ANDROID__)
     // Host adbd.
-    func = server_socket_thread;
-    debug_name = "server";
+    D("transport: local server init");
+    std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #else
+    D("transport: local server init");
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    func = use_qemu_goldfish() ? qemu_socket_thread : server_socket_thread;
-    debug_name = "server";
+    if (use_qemu_goldfish()) {
+        std::thread(qemu_socket_thread, port).detach();
+    } else {
+        std::thread(server_socket_thread, android::base::StringPrintf("tcp:%d", port)).detach();
+    }
+    std::thread(server_socket_thread, android::base::StringPrintf("vsock:%d", port)).detach();
 #endif // !ADB_HOST
-
-    D("transport: local %s init", debug_name);
-    std::thread(func, port).detach();
 }
 
 #if ADB_HOST
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index e433787..46d4bd3 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,25 +34,27 @@
 #include <stdlib.h>
 #include <string.h>
 
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline) {
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
     if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
     strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
 }
 
-boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
-                           const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
-                           std::vector<char>* out) {
+boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+                           const std::vector<char>& second, const std::vector<char>& dtb,
+                           size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
     const size_t page_mask = src.page_size - 1;
 
     int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
     int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
     int64_t ramdisk_actual = (ramdisk.size() + page_mask) & (~page_mask);
     int64_t second_actual = (second.size() + page_mask) & (~page_mask);
+    int64_t dtb_actual = (dtb.size() + page_mask) & (~page_mask);
 
-    int64_t bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
+    int64_t bootimg_size =
+            header_actual + kernel_actual + ramdisk_actual + second_actual + dtb_actual;
     out->resize(bootimg_size);
 
-    boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(out->data());
+    boot_img_hdr_v2* hdr = reinterpret_cast<boot_img_hdr_v2*>(out->data());
 
     *hdr = src;
     memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
@@ -66,13 +68,19 @@
     hdr->second_addr += base;
     hdr->tags_addr += base;
 
-    if (hdr->header_version != 0) {
+    if (hdr->header_version == 1) {
         hdr->header_size = sizeof(boot_img_hdr_v1);
+    } else if (hdr->header_version == 2) {
+        hdr->header_size = sizeof(boot_img_hdr_v2);
+        hdr->dtb_size = dtb.size();
+        hdr->dtb_addr += base;
     }
 
     memcpy(hdr->magic + hdr->page_size, kernel.data(), kernel.size());
     memcpy(hdr->magic + hdr->page_size + kernel_actual, ramdisk.data(), ramdisk.size());
     memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual, second.data(),
            second.size());
+    memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual + second_actual, dtb.data(),
+           dtb.size());
     return hdr;
 }
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index a4e8870..b7cf9bd 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -35,7 +35,7 @@
 #include <string>
 #include <vector>
 
-boot_img_hdr_v1* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
-                           const std::vector<char>& second, size_t base, const boot_img_hdr_v1& src,
-                           std::vector<char>* out);
-void bootimg_set_cmdline(boot_img_hdr_v1* h, const std::string& cmdline);
+boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+                           const std::vector<char>& second, const std::vector<char>& dtb,
+                           size_t base, const boot_img_hdr_v2& src, std::vector<char>* out);
+void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline);
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index f737405..99854c9 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -52,15 +52,17 @@
     // Following appears to have a first time 2% impact on flashing speeds.
 
     // Convert partition_name to a validated mount point and wipe.
-    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
-                                                               fs_mgr_free_fstab);
-    for (auto i = 0; i < fstab->num_entries; i++) {
-        const auto mount_point = fstab->recs[i].mount_point;
-        if (!mount_point) continue;
-        auto partition = android::base::Basename(mount_point);
-        if ("/"s == mount_point) partition = "system";
+    Fstab fstab;
+    ReadDefaultFstab(&fstab);
+
+    for (const auto& entry : fstab) {
+        auto partition = android::base::Basename(entry.mount_point);
+        if ("/" == entry.mount_point) {
+            partition = "system";
+        }
+
         if ((partition + device->GetCurrentSlot()) == partition_name) {
-            fs_mgr_overlayfs_teardown(mount_point);
+            fs_mgr_overlayfs_teardown(entry.mount_point.c_str());
         }
     }
 }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d753f0f..17cab3a 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -92,8 +92,9 @@
 static int64_t target_sparse_limit = -1;
 
 static unsigned g_base_addr = 0x10000000;
-static boot_img_hdr_v1 g_boot_img_hdr = {};
+static boot_img_hdr_v2 g_boot_img_hdr = {};
 static std::string g_cmdline;
+static std::string g_dtb_path;
 
 static bool g_disable_verity = false;
 static bool g_disable_verification = false;
@@ -394,11 +395,13 @@
             "                            Download and boot kernel from RAM.\n"
             " flash:raw PARTITION KERNEL [RAMDISK [SECOND]]\n"
             "                            Create boot image and flash it.\n"
+            " --dtb DTB                  Specify path to DTB for boot image header version 2.\n"
             " --cmdline CMDLINE          Override kernel command line.\n"
             " --base ADDRESS             Set kernel base address (default: 0x10000000).\n"
             " --kernel-offset            Set kernel offset (default: 0x00008000).\n"
             " --ramdisk-offset           Set ramdisk offset (default: 0x01000000).\n"
             " --tags-offset              Set tags offset (default: 0x00000100).\n"
+            " --dtb-offset               Set dtb offset (default: 0x01100000).\n"
             " --page-size BYTES          Set flash page size (default: 2048).\n"
             " --header-version VERSION   Set boot image header version.\n"
             " --os-version MAJOR[.MINOR[.PATCH]]\n"
@@ -448,12 +451,12 @@
     }
 
     // Is this actually a boot image?
-    if (kernel_data.size() < sizeof(boot_img_hdr_v1)) {
+    if (kernel_data.size() < sizeof(boot_img_hdr_v2)) {
         die("cannot load '%s': too short", kernel.c_str());
     }
     if (!memcmp(kernel_data.data(), BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
         if (!g_cmdline.empty()) {
-            bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v1*>(kernel_data.data()), g_cmdline);
+            bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v2*>(kernel_data.data()), g_cmdline);
         }
 
         if (!ramdisk.empty()) die("cannot boot a boot.img *and* ramdisk");
@@ -474,15 +477,26 @@
             die("cannot load '%s': %s", second_stage.c_str(), strerror(errno));
         }
     }
+
+    std::vector<char> dtb_data;
+    if (!g_dtb_path.empty()) {
+        if (g_boot_img_hdr.header_version < 2) {
+                    die("Argument dtb not supported for boot image header version %d\n",
+                        g_boot_img_hdr.header_version);
+        }
+        if (!ReadFileToVector(g_dtb_path, &dtb_data)) {
+            die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno));
+        }
+    }
+
     fprintf(stderr,"creating boot image...\n");
 
     std::vector<char> out;
-    boot_img_hdr_v1* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
-                                                 g_base_addr, g_boot_img_hdr, &out);
+    boot_img_hdr_v2* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
+                                                 dtb_data, g_base_addr, g_boot_img_hdr, &out);
 
     if (!g_cmdline.empty()) bootimg_set_cmdline(boot_image_data, g_cmdline);
     fprintf(stderr, "creating boot image - %zu bytes\n", out.size());
-
     return out;
 }
 
@@ -1586,6 +1600,7 @@
     g_boot_img_hdr.second_addr = 0x00f00000;
     g_boot_img_hdr.tags_addr = 0x00000100;
     g_boot_img_hdr.page_size = 2048;
+    g_boot_img_hdr.dtb_addr = 0x01100000;
 
     const struct option longopts[] = {
         {"base", required_argument, 0, 0},
@@ -1605,6 +1620,8 @@
         {"skip-secondary", no_argument, 0, 0},
         {"slot", required_argument, 0, 0},
         {"tags-offset", required_argument, 0, 0},
+        {"dtb", required_argument, 0, 0},
+        {"dtb-offset", required_argument, 0, 0},
         {"unbuffered", no_argument, 0, 0},
         {"verbose", no_argument, 0, 'v'},
         {"version", no_argument, 0, 0},
@@ -1632,6 +1649,8 @@
                 force_flash = true;
             } else if (name == "header-version") {
                 g_boot_img_hdr.header_version = strtoul(optarg, nullptr, 0);
+            } else if (name == "dtb") {
+                g_dtb_path = optarg;
             } else if (name == "kernel-offset") {
                 g_boot_img_hdr.kernel_addr = strtoul(optarg, 0, 16);
             } else if (name == "os-patch-level") {
@@ -1649,6 +1668,8 @@
                 skip_secondary = true;
             } else if (name == "slot") {
                 slot_override = optarg;
+            } else if (name == "dtb-offset") {
+                g_boot_img_hdr.dtb_addr = strtoul(optarg, 0, 16);
             } else if (name == "tags-offset") {
                 g_boot_img_hdr.tags_addr = strtoul(optarg, 0, 16);
             } else if (name == "unbuffered") {
@@ -1828,7 +1849,6 @@
             if (!args.empty()) ramdisk = next_arg(&args);
             std::string second_stage;
             if (!args.empty()) second_stage = next_arg(&args);
-
             auto data = LoadBootableImage(kernel, ramdisk, second_stage);
             fb->Download("boot.img", data);
             fb->Boot();
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index ded3678..26ce3b2 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -889,19 +889,6 @@
     return true;
 }
 
-bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
-    auto entry = FstabRecToFstabEntry(rec);
-
-    if (!fs_mgr_update_logical_partition(&entry)) {
-        return false;
-    }
-
-    free(rec->blk_device);
-    rec->blk_device = strdup(entry.blk_device.c_str());
-
-    return true;
-}
-
 class CheckpointManager {
   public:
     CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 9d4f280..0482f6c 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;
         }
@@ -686,6 +625,7 @@
     userdata.fs_mgr_flags.logical = true;
     userdata.fs_mgr_flags.quota = true;
     userdata.fs_mgr_flags.late_mount = true;
+    userdata.fs_mgr_flags.formattable = true;
     fstab->emplace_back(userdata);
 }
 
@@ -719,10 +659,10 @@
 }
 
 // Returns fstab entries parsed from the device tree if they exist
-bool ReadFstabFromDt(Fstab* fstab) {
+bool ReadFstabFromDt(Fstab* fstab, bool log) {
     std::string fstab_buf = read_fstab_from_dt();
     if (fstab_buf.empty()) {
-        LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
+        if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
         return false;
     }
 
@@ -730,13 +670,15 @@
         fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
                  fstab_buf.length(), "r"), fclose);
     if (!fstab_file) {
-        PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+        if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
         return false;
     }
 
     if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
-        LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
-               << std::endl << fstab_buf;
+        if (log) {
+            LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
+                   << fstab_buf;
+        }
         return false;
     }
 
@@ -778,7 +720,7 @@
 // Loads the fstab file and combines with fstab entries passed in from device tree.
 bool ReadDefaultFstab(Fstab* fstab) {
     Fstab dt_fstab;
-    ReadFstabFromDt(&dt_fstab);
+    ReadFstabFromDt(&dt_fstab, false);
 
     *fstab = std::move(dt_fstab);
 
@@ -831,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);
@@ -843,35 +787,6 @@
     free(fstab);
 }
 
-/* Add an entry to the fstab, and return 0 on success or -1 on error */
-int fs_mgr_add_entry(struct fstab *fstab,
-                     const char *mount_point, const char *fs_type,
-                     const char *blk_device)
-{
-    struct fstab_rec *new_fstab_recs;
-    int n = fstab->num_entries;
-
-    new_fstab_recs = (struct fstab_rec *)
-                     realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1));
-
-    if (!new_fstab_recs) {
-        return -1;
-    }
-
-    /* A new entry was added, so initialize it */
-     memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec));
-     new_fstab_recs[n].mount_point = strdup(mount_point);
-     new_fstab_recs[n].fs_type = strdup(fs_type);
-     new_fstab_recs[n].blk_device = strdup(blk_device);
-     new_fstab_recs[n].length = 0;
-
-     /* Update the fstab struct */
-     fstab->recs = new_fstab_recs;
-     fstab->num_entries++;
-
-     return 0;
-}
-
 /*
  * Returns the fstab_rec* whose mount_point is path.
  * Returns nullptr if not found.
@@ -972,8 +887,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());
@@ -999,34 +914,15 @@
     return fstab->fs_mgr_flags & MF_VERIFY;
 }
 
-int fs_mgr_is_avb(const struct fstab_rec *fstab)
-{
-    return fstab->fs_mgr_flags & MF_AVB;
-}
-
-int fs_mgr_is_verifyatboot(const struct fstab_rec *fstab)
-{
-    return fstab->fs_mgr_flags & MF_VERIFYATBOOT;
-}
-
 int fs_mgr_is_encryptable(const struct fstab_rec *fstab)
 {
     return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT | MF_FORCEFDEORFBE);
 }
 
-int fs_mgr_is_file_encrypted(const struct fstab_rec *fstab)
-{
-    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)
@@ -1043,26 +939,6 @@
     return fstab->fs_mgr_flags & MF_NOTRIM;
 }
 
-int fs_mgr_is_formattable(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & (MF_FORMATTABLE);
-}
-
-int fs_mgr_is_slotselect(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & MF_SLOTSELECT;
-}
-
-int fs_mgr_is_nofail(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & MF_NOFAIL;
-}
-
-int fs_mgr_is_first_stage_mount(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & MF_FIRST_STAGE_MOUNT;
-}
-
-int fs_mgr_is_latemount(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & MF_LATEMOUNT;
-}
-
 int fs_mgr_is_quota(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_QUOTA;
 }
@@ -1088,10 +964,6 @@
     return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
 }
 
-int fs_mgr_is_fs_verity(const struct fstab_rec* fstab) {
-    return fstab->fs_mgr_flags & MF_FS_VERITY;
-}
-
 FstabEntry BuildGsiSystemFstabEntry() {
     FstabEntry system = {
             .blk_device = "system_gsi",
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index e87332f..1685e50 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -79,7 +79,6 @@
         std::function<void(const std::string& mount_point, int mode)> callback);
 bool fs_mgr_swapon_all(const Fstab& fstab);
 bool fs_mgr_update_logical_partition(FstabEntry* entry);
-bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
 
 int fs_mgr_do_format(const FstabEntry& entry, bool reserve_footer);
 int fs_mgr_do_format(fstab_rec* rec, bool reserve_footer);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 38f96c0..100e076 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;
@@ -69,33 +69,22 @@
 struct fstab* fs_mgr_read_fstab(const char* fstab_path);
 void fs_mgr_free_fstab(struct fstab* fstab);
 
-int fs_mgr_add_entry(struct fstab* fstab, const char* mount_point, const char* fs_type,
-                     const char* blk_device);
 struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path);
 int fs_mgr_is_voldmanaged(const struct fstab_rec* fstab);
 int fs_mgr_is_nonremovable(const struct fstab_rec* fstab);
 int fs_mgr_is_verified(const struct fstab_rec* fstab);
-int fs_mgr_is_verifyatboot(const struct fstab_rec* fstab);
-int fs_mgr_is_avb(const struct fstab_rec* fstab);
 int fs_mgr_is_encryptable(const struct fstab_rec* fstab);
-int fs_mgr_is_file_encrypted(const struct fstab_rec* fstab);
 void fs_mgr_get_file_encryption_modes(const struct fstab_rec* fstab, const char** contents_mode_ret,
                                       const char** filenames_mode_ret);
 int fs_mgr_is_convertible_to_fbe(const struct fstab_rec* fstab);
 int fs_mgr_is_noemulatedsd(const struct fstab_rec* fstab);
 int fs_mgr_is_notrim(const struct fstab_rec* fstab);
-int fs_mgr_is_formattable(const struct fstab_rec* fstab);
-int fs_mgr_is_slotselect(const struct fstab_rec* fstab);
-int fs_mgr_is_nofail(const struct fstab_rec* fstab);
-int fs_mgr_is_first_stage_mount(const struct fstab_rec* fstab);
-int fs_mgr_is_latemount(const struct fstab_rec* fstab);
 int fs_mgr_is_quota(const struct fstab_rec* fstab);
 int fs_mgr_is_logical(const struct fstab_rec* fstab);
 int fs_mgr_is_checkpoint(const struct fstab_rec* fstab);
 int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
 int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
 int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);
-int fs_mgr_is_fs_verity(const struct fstab_rec* fstab);
 
 std::string fs_mgr_get_slot_suffix();
 std::string fs_mgr_get_other_slot_suffix();
@@ -118,19 +107,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
@@ -192,7 +181,7 @@
 using Fstab = std::vector<FstabEntry>;
 
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
-bool ReadFstabFromDt(Fstab* fstab);
+bool ReadFstabFromDt(Fstab* fstab, bool log = true);
 bool ReadDefaultFstab(Fstab* fstab);
 
 // Temporary conversion functions.
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 8f08169..69724f8 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -442,10 +442,6 @@
 }
 
 TEST_F(BuilderTest, block_device_info) {
-    std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
-                                                               fs_mgr_free_fstab);
-    ASSERT_NE(fstab, nullptr);
-
     PartitionOpener opener;
 
     BlockDeviceInfo device_info;
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 1922a69..e2b283a 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -138,38 +138,32 @@
 }
 
 TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
-    auto fstab = fs_mgr_read_fstab("/proc/mounts");
-    ASSERT_NE(fstab, nullptr);
+    Fstab fstab;
+    ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &fstab));
 
     std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "re"),
                                                            endmntent);
     ASSERT_NE(mounts, nullptr);
 
     mntent* mentry;
-    int i = 0;
+    size_t i = 0;
     while ((mentry = getmntent(mounts.get())) != nullptr) {
-        ASSERT_LT(i, fstab->num_entries);
-        auto fsrec = &fstab->recs[i];
+        ASSERT_LT(i, fstab.size());
+        auto& entry = fstab[i];
 
-        std::string mnt_fsname(mentry->mnt_fsname ?: "nullptr");
-        std::string blk_device(fsrec->blk_device ?: "nullptr");
-        EXPECT_EQ(mnt_fsname, blk_device);
-
-        std::string mnt_dir(mentry->mnt_dir ?: "nullptr");
-        std::string mount_point(fsrec->mount_point ?: "nullptr");
-        EXPECT_EQ(mnt_dir, mount_point);
-
-        std::string mnt_type(mentry->mnt_type ?: "nullptr");
-        std::string fs_type(fsrec->fs_type ?: "nullptr");
-        EXPECT_EQ(mnt_type, fs_type);
+        EXPECT_EQ(mentry->mnt_fsname, entry.blk_device);
+        EXPECT_EQ(mentry->mnt_dir, entry.mount_point);
+        EXPECT_EQ(mentry->mnt_type, entry.fs_type);
 
         std::set<std::string> mnt_opts;
-        for (auto& s : android::base::Split(mentry->mnt_opts ?: "nullptr", ",")) {
+        for (auto& s : android::base::Split(mentry->mnt_opts, ",")) {
             mnt_opts.emplace(s);
         }
         std::set<std::string> fs_options;
-        for (auto& s : android::base::Split(fsrec->fs_options ?: "nullptr", ",")) {
-            fs_options.emplace(s);
+        if (!entry.fs_options.empty()) {
+            for (auto& s : android::base::Split(entry.fs_options, ",")) {
+                fs_options.emplace(s);
+            }
         }
         // matches private content in fs_mgr_fstab.c
         static struct flag_list {
@@ -194,42 +188,836 @@
                 {0, 0},
         };
         for (auto f = 0; mount_flags[f].name; ++f) {
-            if (mount_flags[f].flag & fsrec->flags) {
+            if (mount_flags[f].flag & entry.flags) {
                 fs_options.emplace(mount_flags[f].name);
             }
         }
-        if (!(fsrec->flags & MS_RDONLY)) fs_options.emplace("rw");
+        if (!(entry.flags & MS_RDONLY)) {
+            fs_options.emplace("rw");
+        }
         EXPECT_EQ(mnt_opts, fs_options);
         ++i;
     }
+    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/healthd/Android.mk b/healthd/Android.mk
index 80bf84a..2127b96 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -109,6 +109,7 @@
     libbase \
     libutils \
     libcutils \
+    libprocessgroup \
     liblog \
     libm \
     libc \
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 4291212..0dbbc3f 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -66,7 +66,6 @@
         "load_file.cpp",
         "native_handle.cpp",
         "record_stream.cpp",
-        "sched_policy.cpp",
         "sockets.cpp",
         "strdup16to8.cpp",
         "strdup8to16.cpp",
@@ -178,8 +177,12 @@
         "libbase_headers",
         "libcutils_headers",
         "libutils_headers",
+        "libprocessgroup_headers",
     ],
-    export_header_lib_headers: ["libcutils_headers"],
+    export_header_lib_headers: [
+        "libcutils_headers",
+        "libprocessgroup_headers",
+    ],
     local_include_dirs: ["include"],
 
     cflags: [
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index cf91b76..538ff6b 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -17,67 +17,10 @@
 #ifndef __CUTILS_SCHED_POLICY_H
 #define __CUTILS_SCHED_POLICY_H
 
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 /*
- * Check if Linux kernel enables CPUSETS feature.
- *
- * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ * For backwards compatibility only
+ * New users should include processgroup/sched_policy.h directly
  */
-extern bool cpusets_enabled();
-
-/*
- * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
- * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
- *
- * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
- */
-extern bool schedboost_enabled();
-
-/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
-typedef enum {
-    SP_DEFAULT = -1,
-    SP_BACKGROUND = 0,
-    SP_FOREGROUND = 1,
-    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
-    SP_AUDIO_APP = 3,
-    SP_AUDIO_SYS = 4,
-    SP_TOP_APP = 5,
-    SP_RT_APP = 6,
-    SP_RESTRICTED = 7,
-    SP_CNT,
-    SP_MAX = SP_CNT - 1,
-    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
-} SchedPolicy;
-
-extern int set_cpuset_policy(int tid, SchedPolicy policy);
-
-/* Assign thread tid to the cgroup associated with the specified policy.
- * If the thread is a thread group leader, that is it's gettid() == getpid(),
- * then the other threads in the same thread group are _not_ affected.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -errno for error.
- */
-extern int set_sched_policy(int tid, SchedPolicy policy);
-
-/* Return the policy associated with the cgroup of thread tid via policy pointer.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -1 for error and set errno.
- */
-extern int get_sched_policy(int tid, SchedPolicy *policy);
-
-/* Return a displayable string corresponding to policy.
- * Return value: non-NULL NUL-terminated name of unspecified length;
- * the caller is responsible for displaying the useful part of the string.
- */
-extern const char *get_sched_policy_name(SchedPolicy policy);
-
-#ifdef __cplusplus
-}
-#endif
+#include <processgroup/sched_policy.h>
 
 #endif /* __CUTILS_SCHED_POLICY_H */ 
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 7884190..72ae559 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -59,6 +59,7 @@
     "libcutils",
     "liblog",
     "libbase",
+    "libprocessgroup",
 ]
 
 cc_test {
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c38279d..d04a79a 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,10 +1,45 @@
+cc_library_headers {
+    name: "libprocessgroup_headers",
+    vendor_available: true,
+    recovery_available: true,
+    host_supported: true,
+    export_include_dirs: ["include"],
+    target: {
+        linux_bionic: {
+            enabled: true,
+        },
+        windows: {
+            enabled: true,
+        },
+    },
+}
+
 cc_library {
-    srcs: ["processgroup.cpp"],
+    srcs: [
+        "processgroup.cpp",
+        "sched_policy.cpp",
+    ],
     name: "libprocessgroup",
     host_supported: true,
     recovery_available: true,
-    shared_libs: ["libbase"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
+    // for cutils/android_filesystem_config.h
+    header_libs: [
+        "libcutils_headers",
+        "libprocessgroup_headers",
+    ],
     export_include_dirs: ["include"],
+    export_header_lib_headers: [
+        "libprocessgroup_headers",
+    ],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
new file mode 100644
index 0000000..79a32fd
--- /dev/null
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Check if Linux kernel enables CPUSETS feature.
+ *
+ * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
+ */
+extern bool cpusets_enabled();
+
+/*
+ * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
+ * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
+ *
+ * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
+ */
+extern bool schedboost_enabled();
+
+/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
+typedef enum {
+    SP_DEFAULT = -1,
+    SP_BACKGROUND = 0,
+    SP_FOREGROUND = 1,
+    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
+    SP_AUDIO_APP = 3,
+    SP_AUDIO_SYS = 4,
+    SP_TOP_APP = 5,
+    SP_RT_APP = 6,
+    SP_RESTRICTED = 7,
+    SP_CNT,
+    SP_MAX = SP_CNT - 1,
+    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
+} SchedPolicy;
+
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
+/* Assign thread tid to the cgroup associated with the specified policy.
+ * If the thread is a thread group leader, that is it's gettid() == getpid(),
+ * then the other threads in the same thread group are _not_ affected.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -errno for error.
+ */
+extern int set_sched_policy(int tid, SchedPolicy policy);
+
+/* Return the policy associated with the cgroup of thread tid via policy pointer.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -1 for error and set errno.
+ */
+extern int get_sched_policy(int tid, SchedPolicy *policy);
+
+/* Return a displayable string corresponding to policy.
+ * Return value: non-NULL NUL-terminated name of unspecified length;
+ * the caller is responsible for displaying the useful part of the string.
+ */
+extern const char *get_sched_policy_name(SchedPolicy policy);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 9df8dd9..8d2ac3d 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -42,7 +42,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <private/android_filesystem_config.h>
+#include <cutils/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
diff --git a/libcutils/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
similarity index 99%
rename from libcutils/sched_policy.cpp
rename to libprocessgroup/sched_policy.cpp
index 3fa548f..f95d7e4 100644
--- a/libcutils/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -14,7 +14,7 @@
 ** limitations under the License.
 */
 
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
 
 #define LOG_TAG "SchedPolicy"
 
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 8ad339f..2ec4754 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -67,3 +67,18 @@
 
     cflags: ["-Werror"],
 }
+
+python_binary_host {
+    name: "simg_dump.py",
+    main: "simg_dump.py",
+    srcs: ["simg_dump.py"],
+    version: {
+        py2: {
+            embedded_launcher: true,
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
deleted file mode 100644
index 05e68bc..0000000
--- a/libsparse/Android.mk
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2010 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := simg_dump.py
-LOCAL_SRC_FILES := simg_dump.py
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_IS_HOST_MODULE := true
-LOCAL_CFLAGS := -Werror
-include $(BUILD_PREBUILT)
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index d1b8271..c90f5b2 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -212,6 +212,7 @@
         "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/TestUtils.cpp",
         "tests/UnwindOfflineTest.cpp",
         "tests/UnwindTest.cpp",
         "tests/UnwinderTest.cpp",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index f319971..9e6bcd4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -22,6 +22,8 @@
 #include <mutex>
 #include <string>
 
+#include <android-base/stringprintf.h>
+
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Maps.h>
@@ -311,4 +313,16 @@
   return *reinterpret_cast<std::string*>(id);
 }
 
+std::string MapInfo::GetPrintableBuildID() {
+  std::string raw_build_id = GetBuildID();
+  if (raw_build_id.empty()) {
+    return "";
+  }
+  std::string printable_build_id;
+  for (const char& c : raw_build_id) {
+    printable_build_id += android::base::StringPrintf("%02x", c);
+  }
+  return printable_build_id;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 0dd95cf..2734cf8 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -247,7 +247,7 @@
         // or the pc in the first frame is in a valid map.
         // This allows for a case where the code jumps into the middle of
         // nowhere, but there is no other unwind information after that.
-        if (frames_.size() != 2 || maps_->Find(frames_[0].pc) != nullptr) {
+        if (frames_.size() > 2 || (frames_.size() > 0 && maps_->Find(frames_[0].pc) != nullptr)) {
           // Remove the speculative frame.
           frames_.pop_back();
         }
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 5143ff1..e938986 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -84,8 +84,12 @@
 
   bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
 
+  // Returns the raw build id read from the elf data.
   std::string GetBuildID();
 
+  // Returns the printable version of the build id (hex dump of raw data).
+  std::string GetPrintableBuildID();
+
  private:
   MapInfo(const MapInfo&) = delete;
   void operator=(const MapInfo&) = delete;
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index 3b89c59..ea9befc 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -67,6 +67,7 @@
   MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
 
   EXPECT_EQ("", info.GetBuildID());
+  EXPECT_EQ("", info.GetPrintableBuildID());
 }
 
 TEST_F(MapInfoGetBuildIDTest, from_elf) {
@@ -74,6 +75,7 @@
   elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
 
   EXPECT_EQ("FAKE_BUILD_ID", map_info_->GetBuildID());
+  EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
 }
 
 void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
@@ -172,6 +174,7 @@
   InitElfData(tf_->fd);
 
   EXPECT_EQ("ELF_BUILDID", map_info_->GetBuildID());
+  EXPECT_EQ("454c465f4255494c444944", map_info_->GetPrintableBuildID());
 }
 
 TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists_in_memory) {
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
new file mode 100644
index 0000000..e76f5f8
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 <malloc.h>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+namespace unwindstack {
+
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data) {
+  static constexpr size_t kNumLeakLoops = 200;
+  static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024;
+
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
+  for (size_t i = 0; i < kNumLeakLoops; i++) {
+    unwind_func(data);
+
+    size_t allocated_bytes = mallinfo().uordblks;
+    if (first_allocated_bytes == 0) {
+      first_allocated_bytes = allocated_bytes;
+    } else if (last_allocated_bytes > first_allocated_bytes) {
+      // Check that the memory did not increase too much over the first loop.
+      ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes);
+    }
+    last_allocated_bytes = allocated_bytes;
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index 8c31aa6..a4d7b9b 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -50,6 +50,8 @@
   return ready;
 }
 
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0588a84..b5feb38 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -43,6 +43,7 @@
 #include <unwindstack/Unwinder.h>
 
 #include "ElfTestUtils.h"
+#include "TestUtils.h"
 
 namespace unwindstack {
 
@@ -901,6 +902,43 @@
   EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp);
 }
 
+struct LeakType {
+  LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory)
+      : maps(maps), regs(regs), process_memory(process_memory) {}
+
+  Maps* maps;
+  Regs* regs;
+  std::shared_ptr<Memory>& process_memory;
+};
+
+static void OfflineUnwind(void* data) {
+  LeakType* leak_data = reinterpret_cast<LeakType*>(data);
+
+  std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+  JitDebug jit_debug(leak_data->process_memory);
+  Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
+  unwinder.Unwind();
+  ASSERT_EQ(76U, unwinder.NumFrames());
+}
+
+TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) {
+  ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
+
+  MemoryOfflineParts* memory = new MemoryOfflineParts;
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "descriptor1.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
+  for (size_t i = 0; i < 7; i++) {
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+  }
+  process_memory_.reset(memory);
+
+  LeakType data(maps_.get(), regs_.get(), process_memory_);
+  TestCheckForLeaks(OfflineUnwind, &data);
+}
+
 // The eh_frame_hdr data is present but set to zero fdes. This should
 // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
 // No .gnu_debugdata section in the elf file, so no symbols.
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index c747eab..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -198,6 +198,21 @@
   OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID);
 }
 
+static void LocalUnwind(void* data) {
+  TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data);
+  OuterFunction(*test_type);
+}
+
+TEST_F(UnwindTest, local_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
+TEST_F(UnwindTest, local_use_from_pid_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
   *completed = false;
   // Need to sleep before attempting first ptrace. Without this, on the
@@ -279,6 +294,57 @@
       << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
+static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    OuterFunction(TEST_TYPE_REMOTE);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
+
+  bool completed;
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+
+  TestCheckForLeaks(unwind_func, &pid);
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
+}
+
+static void RemoteUnwind(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  RemoteMaps maps(*pid);
+  ASSERT_TRUE(maps.Parse());
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwind);
+}
+
+static void RemoteUnwindFromPid(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  UnwinderFromPid unwinder(512, *pid);
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
+  unwinder.SetRegs(regs.get());
+
+  VerifyUnwind(&unwinder, kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwindFromPid);
+}
+
 TEST_F(UnwindTest, from_context) {
   std::atomic_int tid(0);
   std::thread thread([&]() {
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 49aeeb3..d88531f 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -749,6 +749,23 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
 }
 
+// Verify that a speculative frame does not cause a crash when it wasn't
+// really added due to a filter.
+TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) {
+  regs_.set_pc(0x23000);
+  regs_.set_sp(0x10000);
+  regs_.FakeSetReturnAddress(0x23100);
+  regs_.FakeSetReturnAddressValid(true);
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+
+  std::vector<std::string> skip_names{"libanother.so"};
+  unwinder.Unwind(&skip_names);
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+  ASSERT_EQ(0U, unwinder.NumFrames());
+}
+
 // Verify that an unwind stops when a frame is in given suffix.
 TEST_F(UnwinderTest, map_ignore_suffixes) {
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 3e8417e..fb7ca32 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,11 +22,13 @@
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
+        "libprocessgroup_headers",
     ],
     export_header_lib_headers: [
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
+        "libprocessgroup_headers",
     ],
     export_include_dirs: ["include"],
 
@@ -82,6 +84,7 @@
 
             shared_libs: [
                 "libcutils",
+                "libprocessgroup",
                 "libdl",
                 "libvndksupport",
             ],
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 64bc402..31ca138 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -36,7 +36,7 @@
 
 #include <utils/Log.h>
 
-#include <cutils/sched_policy.h>
+#include <processgroup/sched_policy.h>
 
 #if defined(__ANDROID__)
 # define __android_unused
diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp
index 5f0a51f..24a745a 100644
--- a/libutils/Unicode.cpp
+++ b/libutils/Unicode.cpp
@@ -275,25 +275,6 @@
   return ss-s;
 }
 
-
-char16_t *strncpy16(char16_t *dst, const char16_t *src, size_t n)
-{
-  char16_t *q = dst;
-  const char16_t *p = src;
-  char ch;
-
-  while (n) {
-    n--;
-    *q++ = ch = *p++;
-    if ( !ch )
-      break;
-  }
-
-  *q = 0;
-
-  return dst;
-}
-
 size_t strnlen16(const char16_t *s, size_t maxlen)
 {
   const char16_t *ss = s;
diff --git a/libutils/include/utils/Unicode.h b/libutils/include/utils/Unicode.h
index 61a1b4f..a2aaa47 100644
--- a/libutils/include/utils/Unicode.h
+++ b/libutils/include/utils/Unicode.h
@@ -28,7 +28,6 @@
 size_t strlen16(const char16_t *);
 size_t strnlen16(const char16_t *, size_t);
 char16_t *strcpy16(char16_t *, const char16_t *);
-char16_t *strncpy16(char16_t *, const char16_t *, size_t);
 char16_t *strstr16(const char16_t*, const char16_t*);
 
 // Version of comparison that supports embedded NULs.
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index 903d0e2..f9ed57c 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -5,6 +5,7 @@
     shared_libs: [
         "libcutils",
         "liblog",
+        "libprocessgroup",
     ],
     static_libs: [
         "libstatslogc",
diff --git a/logcat/Android.bp b/logcat/Android.bp
index 0543aba..5030b15 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -24,8 +24,8 @@
     ],
     shared_libs: [
         "libbase",
-        "libcutils",
         "libpcrecpp",
+        "libprocessgroup",
     ],
     static_libs: ["liblog"],
     logtags: ["event.logtags"],
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 87bc6ae..15e07fe 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -49,11 +49,11 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <log/logprint.h>
 #include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
 #include <system/thread_defs.h>
 
 #include <pcrecpp.h>
diff --git a/logd/Android.bp b/logd/Android.bp
index 3abfc21..360f2fe 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -73,8 +73,16 @@
         "libcutils",
         "libbase",
         "libpackagelistparser",
+        "libprocessgroup",
         "libcap",
     ],
 
     cflags: ["-Werror"],
 }
+
+
+prebuilt_etc {
+    name: "logtagd.rc",
+    src: "logtagd.rc",
+    sub_dir: "init",
+}
diff --git a/logd/Android.mk b/logd/Android.mk
deleted file mode 100644
index aafa28d..0000000
--- a/logd/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := logtagd.rc
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
-
-include $(BUILD_PREBUILT)
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 470ffed..a21555c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -111,7 +111,7 @@
 }
 
 std::map<std::string, std::string> LogAudit::populateDenialMap() {
-    std::ifstream bug_file("/system/etc/selinux/selinux_denial_metadata");
+    std::ifstream bug_file("/vendor/etc/selinux/selinux_denial_metadata");
     std::string line;
     // allocate a map for the static map pointer in auditParse to keep track of,
     // this function only runs once
diff --git a/logd/main.cpp b/logd/main.cpp
index 8c38d9a..fd3cdf8 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,12 +38,12 @@
 #include <android-base/macros.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
-#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
+#include <processgroup/sched_policy.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
diff --git a/mkbootimg/mkbootimg.py b/mkbootimg/mkbootimg.py
index 859b1e4..92b11a5 100644
--- a/mkbootimg/mkbootimg.py
+++ b/mkbootimg/mkbootimg.py
@@ -62,7 +62,13 @@
 
 
 def write_header(args):
+    BOOT_IMAGE_HEADER_V1_SIZE = 1648
+    BOOT_IMAGE_HEADER_V2_SIZE = 1660
     BOOT_MAGIC = 'ANDROID!'.encode()
+
+    if (args.header_version > 2):
+        raise ValueError('Boot header version %d not supported' % args.header_version)
+
     args.output.write(pack('8s', BOOT_MAGIC))
     args.output.write(pack('10I',
         filesize(args.kernel),                          # size in bytes
@@ -99,8 +105,12 @@
             args.output.write(pack('Q', get_recovery_dtbo_offset(args))) # recovery dtbo offset
         else:
             args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
-        args.output.write(pack('I', args.output.tell() + 4))         # size of boot header
 
+    # Populate boot image header size for header versions 1 and 2.
+    if args.header_version == 1:
+        args.output.write(pack('I', BOOT_IMAGE_HEADER_V1_SIZE))
+    elif args.header_version == 2:
+        args.output.write(pack('I', BOOT_IMAGE_HEADER_V2_SIZE))
 
     if args.header_version > 1:
         args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 1871ca7..5a6f41b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -24,6 +24,26 @@
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
 
+# Start of runtime APEX compatibility.
+#
+# Meta-comment:
+# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
+# entries need to be associated with something that goes into /system.
+# init-debug.rc qualifies but it could be anything else in /system until soong
+# supports creation of symlinks. http://b/123333111
+#
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# End of runtime APEX compatibilty.
+
 include $(BUILD_PREBUILT)
 
 #######################################
@@ -129,19 +149,6 @@
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
 
-# Start of runtime APEX compatibility.
-# Keeping the appearance of files/dirs having old locations for apps that have
-# come to rely on them.
-
-# http://b/121248172 - create a link from /system/usr/icu to
-# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
-# A symlink can't overwrite a directory and the /system/usr/icu directory once
-# existed so the required structure must be created whatever we find.
-LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
-LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
-
-# End of runtime APEX compatibilty.
-
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 461184a..a416825 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -32,6 +32,92 @@
 namespace.default.asan.search.paths +=           /odm/${LIB}
 
 ###############################################################################
+# APEX related namespaces.
+###############################################################################
+
+additional.namespaces = runtime,conscrypt,media,resolv
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+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
+namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+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
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "media" APEX namespace
+#
+# This namespace is for libraries within the media APEX.
+###############################################################################
+namespace.media.isolated = true
+namespace.media.visible = true
+
+namespace.media.search.paths = /apex/com.android.media/${LIB}
+namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
+
+namespace.media.links = default
+namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
+namespace.media.link.default.shared_libs += libandroid.so
+namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
+namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# "conscrypt" APEX namespace
+#
+# This namespace is for libraries within the conscrypt APEX.
+###############################################################################
+namespace.conscrypt.isolated = true
+namespace.conscrypt.visible = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
+namespace.conscrypt.links = default
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+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 54e7c7e..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,12 +116,15 @@
 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
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 ###############################################################################
 namespace.runtime.isolated = true
+namespace.runtime.visible = true
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
@@ -148,6 +149,7 @@
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 ###############################################################################
@@ -167,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
@@ -329,6 +347,9 @@
 # partition (VNDK and LLNDK libraries) are not loaded here but from the
 # separate namespace 'system'. The delegation to the system namespace is done
 # via the 'namespace.default.link.system.shared_libs' property below.
+#
+# '#VNDK27#' TAG is only for building ld.config.27.txt for backward
+# compatibility. (TODO:b/123390078) Move them to a separate file.
 ###############################################################################
 namespace.default.isolated = true
 namespace.default.visible = true
@@ -338,11 +359,17 @@
 
 namespace.default.permitted.paths  = /odm
 namespace.default.permitted.paths += /vendor
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
+#VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
 
 namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.default.asan.search.paths +=           /odm/${LIB}
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/hw
+#VNDK27#namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/egl
+#VNDK27#namespace.default.asan.search.paths +=           /vendor/${LIB}/egl
 
 namespace.default.asan.permitted.paths  = /data/asan/odm
 namespace.default.asan.permitted.paths +=           /odm
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 39f69ca..c97baeb 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,21 +57,25 @@
 
 # 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
 namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
 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
 #
 # This namespace pulls in externally accessible libs from the Runtime APEX.
 ###############################################################################
 namespace.runtime.isolated = true
+namespace.runtime.visible = true
 
 # Keep in sync with the default namespace in the com.android.runtime APEX
 # ld.config.txt.
@@ -97,6 +101,7 @@
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
 namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 ###############################################################################
@@ -116,6 +121,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/init.rc b/rootdir/init.rc
index 537bf86..d081666 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -47,7 +47,7 @@
 
     # Mix device-specific information into the entropy pool
     copy /proc/cmdline /dev/urandom
-    copy /default.prop /dev/urandom
+    copy /system/etc/prop.default /dev/urandom
 
     symlink /proc/self/fd/0 /dev/stdin
     symlink /proc/self/fd/1 /dev/stdout
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 79bed7b..450be66 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -88,6 +88,7 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
 $(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
 $(LOCAL_BUILT_MODULE): PRIVATE_COMP_CHECK_SCRIPT := $(compatibility_check_script)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_TAG := \#VNDK$(vndk_version)\#
 deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
   $(vndkprivate_libraries_file)
 ifeq ($(check_backward_compatibility),true)
@@ -114,10 +115,12 @@
 	paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
 	sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
 
-	$(hide) sed -i.bak -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
-	$(hide) sed -i.bak -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@
-	$(hide) sed -i.bak -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@
-	$(hide) sed -i.bak -e 's?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g' $@
+	$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
+	$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
+	$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
+	$(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
+	$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
+	$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
 	$(hide) rm -f $@.bak
 
 ld_config_template :=