Merge "Multi-threaded Keystore"
diff --git a/adb/adb.h b/adb/adb.h
index 8c37c4b..e2911e8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -59,7 +59,7 @@
 std::string adb_version();
 
 // Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 41
+#define ADB_SERVER_VERSION 40
 
 using TransportId = uint64_t;
 class atransport;
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 611b239..91b73a9 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -28,7 +28,6 @@
 #include <string>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 
 // All of these tests fail on Windows because they use the C Runtime open(),
 // but the adb_io APIs expect file descriptors from adb_open(). This could
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index a8ec5fb..a024a89 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -41,6 +41,11 @@
                const char* tag, const char* file, unsigned int line,
                const char* message) {
     android::base::StderrLogger(id, severity, tag, file, line, message);
+#if defined(_WIN32)
+    // stderr can be buffered on Windows (and setvbuf doesn't seem to work), so explicitly flush.
+    fflush(stderr);
+#endif
+
 #if !ADB_HOST
     // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
     // doesn't result in exponential logging.
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 341323f..870f6f0 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,8 +30,8 @@
 
 #include "sysdeps.h"
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
-#include <android-base/test_utils.h>
 
 #ifdef _WIN32
 static std::string subdir(const char* parent, const char* child) {
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 0008f72..7f37c45 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -30,7 +30,6 @@
 #include "android-base/file.h"
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
-#include "android-base/test_utils.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index 10b6090..f2ca63b 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -332,13 +332,6 @@
             return;
         }
 
-        rc = libusb_set_interface_alt_setting(handle.get(), interface_num, 0);
-        if (rc != 0) {
-            LOG(WARNING) << "failed to set interface alt setting for device '" << device_serial
-                         << "'" << libusb_error_name(rc);
-            return;
-        }
-
         for (uint8_t endpoint : {bulk_in, bulk_out}) {
             rc = libusb_clear_halt(handle.get(), endpoint);
             if (rc != 0) {
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 49baf36..e380c84 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -136,8 +136,8 @@
     io_service_t             usbDevice;
     io_service_t             usbInterface;
     IOCFPlugInInterface      **plugInInterface = NULL;
-    IOUSBInterfaceInterface220  **iface = NULL;
-    IOUSBDeviceInterface197  **dev = NULL;
+    IOUSBInterfaceInterface500  **iface = NULL;
+    IOUSBDeviceInterface500  **dev = NULL;
     HRESULT                  result;
     SInt32                   score;
     uint32_t                 locationId;
@@ -163,7 +163,7 @@
         //* This gets us the interface object
         result = (*plugInInterface)->QueryInterface(
             plugInInterface,
-            CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
+            CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500), (LPVOID*)&iface);
         //* We only needed the plugin to get the interface, so discard it
         (*plugInInterface)->Release(plugInInterface);
         if (result || !iface) {
@@ -209,7 +209,7 @@
         }
 
         result = (*plugInInterface)->QueryInterface(plugInInterface,
-            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
+            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500), (LPVOID*)&dev);
         //* only needed this to query the plugin
         (*plugInInterface)->Release(plugInInterface);
         if (result || !dev) {
diff --git a/adb/sysdeps/stat_test.cpp b/adb/sysdeps/stat_test.cpp
index 2c2e0ee..67155d9 100644
--- a/adb/sysdeps/stat_test.cpp
+++ b/adb/sysdeps/stat_test.cpp
@@ -16,7 +16,7 @@
 
 #include <string>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 
 #include "adb_utils.h"
diff --git a/adb/sysdeps_win32_test.cpp b/adb/sysdeps_win32_test.cpp
index 529b212..183cd5b 100644
--- a/adb/sysdeps_win32_test.cpp
+++ b/adb/sysdeps_win32_test.cpp
@@ -18,7 +18,7 @@
 
 #include "sysdeps.h"
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 
 TEST(sysdeps_win32, adb_getenv) {
     // Insert all test env vars before first call to adb_getenv() which will
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 03a9f30..c2d4917 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1013,9 +1013,10 @@
 #if ADB_HOST
                 kFeatureApex
 #endif
-        // Increment ADB_SERVER_VERSION whenever the feature list changes to
-        // make sure that the adb client and server features stay in sync
-        // (http://b/24370690).
+        // Increment ADB_SERVER_VERSION when adding a feature that adbd needs
+        // to know about. Otherwise, the client can be stuck running an old
+        // version of the server even after upgrading their copy of adb.
+        // (http://b/24370690)
     };
 
     return *features;
diff --git a/adb/transport_fd.cpp b/adb/transport_fd.cpp
index ec61279..a93e68a 100644
--- a/adb/transport_fd.cpp
+++ b/adb/transport_fd.cpp
@@ -85,18 +85,9 @@
             if (pfds[0].revents) {
                 if ((pfds[0].revents & POLLOUT)) {
                     std::lock_guard<std::mutex> lock(this->write_mutex_);
-                    WriteResult result = DispatchWrites();
-                    switch (result) {
-                        case WriteResult::Error:
-                            *error = "write failed";
-                            return;
-
-                        case WriteResult::Completed:
-                            writable_ = true;
-                            break;
-
-                        case WriteResult::TryAgain:
-                            break;
+                    if (DispatchWrites() == WriteResult::Error) {
+                        *error = "write failed";
+                        return;
                     }
                 }
 
@@ -179,13 +170,14 @@
 
     WriteResult DispatchWrites() REQUIRES(write_mutex_) {
         CHECK(!write_buffer_.empty());
-        if (!writable_) {
-            return WriteResult::TryAgain;
-        }
-
         auto iovs = write_buffer_.iovecs();
         ssize_t rc = adb_writev(fd_.get(), iovs.data(), iovs.size());
         if (rc == -1) {
+            if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                writable_ = false;
+                return WriteResult::TryAgain;
+            }
+
             return WriteResult::Error;
         } else if (rc == 0) {
             errno = 0;
@@ -194,6 +186,7 @@
 
         // TODO: Implement a more efficient drop_front?
         write_buffer_.take_front(rc);
+        writable_ = write_buffer_.empty();
         if (write_buffer_.empty()) {
             return WriteResult::Completed;
         }
@@ -211,7 +204,12 @@
         if (!packet->payload.empty()) {
             write_buffer_.append(std::make_unique<IOVector::block_type>(std::move(packet->payload)));
         }
-        return DispatchWrites() != WriteResult::Error;
+
+        WriteResult result = DispatchWrites();
+        if (result == WriteResult::TryAgain) {
+            WakeThread();
+        }
+        return result != WriteResult::Error;
     }
 
     std::thread thread_;
diff --git a/adb/types.h b/adb/types.h
index 0c71c3a..0090c98 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -108,7 +108,10 @@
         CHECK_EQ(0ULL, capacity_);
         CHECK_EQ(0ULL, size_);
         if (size != 0) {
-            data_ = std::make_unique<char[]>(size);
+            // This isn't std::make_unique because that's equivalent to `new char[size]()`, which
+            // value-initializes the array instead of leaving it uninitialized. As an optimization,
+            // call new without parentheses to avoid this costly initialization.
+            data_.reset(new char[size]);
             capacity_ = size;
             size_ = size;
         }
diff --git a/base/file.cpp b/base/file.cpp
index 3834ed4..d5bb7fe 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -18,7 +18,10 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <ftw.h>
 #include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -28,19 +31,144 @@
 #include <string>
 #include <vector>
 
-#include "android-base/logging.h"
-#include "android-base/macros.h"  // For TEMP_FAILURE_RETRY on Darwin.
-#include "android-base/unique_fd.h"
-#include "android-base/utf8.h"
-
 #if defined(__APPLE__)
 #include <mach-o/dyld.h>
 #endif
 #if defined(_WIN32)
+#include <direct.h>
 #include <windows.h>
 #define O_NOFOLLOW 0
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
 #endif
 
+#include "android-base/logging.h"  // and must be after windows.h for ERROR
+#include "android-base/macros.h"   // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/unique_fd.h"
+#include "android-base/utf8.h"
+
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return -1;
+  }
+  // Use open() to match the close() that TemporaryFile's destructor does.
+  // Use O_BINARY to match base file APIs.
+  return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+  if (_mktemp(template_name) == nullptr) {
+    return nullptr;
+  }
+  if (_mkdir(template_name) == -1) {
+    return nullptr;
+  }
+  return template_name;
+}
+#endif
+
+namespace {
+
+std::string GetSystemTempDir() {
+#if defined(__ANDROID__)
+  const auto* tmpdir = getenv("TMPDIR");
+  if (tmpdir == nullptr) tmpdir = "/data/local/tmp";
+  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+    return tmpdir;
+  }
+  // Tests running in app context can't access /data/local/tmp,
+  // so try current directory if /data/local/tmp is not accessible.
+  return ".";
+#elif defined(_WIN32)
+  char tmp_dir[MAX_PATH];
+  DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);  // checks TMP env
+  CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+  CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+  // GetTempPath() returns a path with a trailing slash, but init()
+  // does not expect that, so remove it.
+  CHECK_EQ(tmp_dir[result - 1], '\\');
+  tmp_dir[result - 1] = '\0';
+  return tmp_dir;
+#else
+  const auto* tmpdir = getenv("TMPDIR");
+  if (tmpdir == nullptr) tmpdir = "/tmp";
+  return tmpdir;
+#endif
+}
+
+}  // namespace
+
+TemporaryFile::TemporaryFile() {
+  init(GetSystemTempDir());
+}
+
+TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
+  init(tmp_dir);
+}
+
+TemporaryFile::~TemporaryFile() {
+  if (fd != -1) {
+    close(fd);
+  }
+  if (remove_file_) {
+    unlink(path);
+  }
+}
+
+int TemporaryFile::release() {
+  int result = fd;
+  fd = -1;
+  return result;
+}
+
+void TemporaryFile::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+  fd = mkstemp(path);
+}
+
+TemporaryDir::TemporaryDir() {
+  init(GetSystemTempDir());
+}
+
+TemporaryDir::~TemporaryDir() {
+  if (!remove_dir_and_contents_) return;
+
+  auto callback = [](const char* child, const struct stat*, int file_type, struct FTW*) -> int {
+    switch (file_type) {
+      case FTW_D:
+      case FTW_DP:
+      case FTW_DNR:
+        if (rmdir(child) == -1) {
+          PLOG(ERROR) << "rmdir " << child;
+        }
+        break;
+      case FTW_NS:
+      default:
+        if (rmdir(child) != -1) break;
+        // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
+        FALLTHROUGH_INTENDED;
+      case FTW_F:
+      case FTW_SL:
+      case FTW_SLN:
+        if (unlink(child) == -1) {
+          PLOG(ERROR) << "unlink " << child;
+        }
+        break;
+    }
+    return 0;
+  };
+
+  nftw(path, callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
+}
+
+bool TemporaryDir::init(const std::string& tmp_dir) {
+  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(), OS_PATH_SEPARATOR);
+  return (mkdtemp(path) != nullptr);
+}
+
 namespace android {
 namespace base {
 
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 6794652..f64e81c 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -24,8 +24,6 @@
 
 #include <string>
 
-#include "android-base/test_utils.h"
-
 #if !defined(_WIN32)
 #include <pwd.h>
 #endif
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index 86d537d..f8748b5 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -18,8 +18,10 @@
 
 #include <sys/stat.h>
 #include <sys/types.h>
+
 #include <string>
 
+#include <android-base/macros.h>
 #include "android-base/off64_t.h"
 
 #if !defined(_WIN32) && !defined(O_BINARY)
@@ -32,6 +34,46 @@
 #define O_CLOEXEC O_NOINHERIT
 #endif
 
+class TemporaryFile {
+ public:
+  TemporaryFile();
+  explicit TemporaryFile(const std::string& tmp_dir);
+  ~TemporaryFile();
+
+  // Release the ownership of fd, caller is reponsible for closing the
+  // fd or stream properly.
+  int release();
+  // Don't remove the temporary file in the destructor.
+  void DoNotRemove() { remove_file_ = false; }
+
+  int fd;
+  char path[1024];
+
+ private:
+  void init(const std::string& tmp_dir);
+
+  bool remove_file_ = true;
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
+};
+
+class TemporaryDir {
+ public:
+  TemporaryDir();
+  ~TemporaryDir();
+  // Don't remove the temporary dir in the destructor.
+  void DoNotRemove() { remove_dir_and_contents_ = false; }
+
+  char path[1024];
+
+ private:
+  bool init(const std::string& tmp_dir);
+
+  bool remove_dir_and_contents_ = true;
+
+  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
+};
+
 namespace android {
 namespace base {
 
diff --git a/base/include/android-base/test_utils.h b/base/include/android-base/test_utils.h
index 2abe68e..b20f278 100644
--- a/base/include/android-base/test_utils.h
+++ b/base/include/android-base/test_utils.h
@@ -19,44 +19,9 @@
 #include <regex>
 #include <string>
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
 
-class TemporaryFile {
- public:
-  TemporaryFile();
-  explicit TemporaryFile(const std::string& tmp_dir);
-  ~TemporaryFile();
-
-  // Release the ownership of fd, caller is reponsible for closing the
-  // fd or stream properly.
-  int release();
-  // Don't remove the temporary file in the destructor.
-  void DoNotRemove() { remove_file_ = false; }
-
-  int fd;
-  char path[1024];
-
- private:
-  void init(const std::string& tmp_dir);
-
-  bool remove_file_ = true;
-
-  DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
-};
-
-class TemporaryDir {
- public:
-  TemporaryDir();
-  ~TemporaryDir();
-
-  char path[1024];
-
- private:
-  bool init(const std::string& tmp_dir);
-
-  DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
-};
-
 class CapturedStdFd {
  public:
   CapturedStdFd(int std_fd);
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 57fde6f..7e89723 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -25,7 +25,6 @@
 #include <string>
 
 #include "android-base/file.h"
-#include "android-base/test_utils.h"
 #include "android-base/unique_fd.h"
 
 TEST(mapped_file, smoke) {
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 4d9466b..36b4cdf 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -22,109 +22,11 @@
 #include <sys/stat.h>
 #include <unistd.h>
 
-#if defined(_WIN32)
-#include <windows.h>
-#include <direct.h>
-#define OS_PATH_SEPARATOR '\\'
-#else
-#define OS_PATH_SEPARATOR '/'
-#endif
-
 #include <string>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
 
-#ifdef _WIN32
-int mkstemp(char* template_name) {
-  if (_mktemp(template_name) == nullptr) {
-    return -1;
-  }
-  // Use open() to match the close() that TemporaryFile's destructor does.
-  // Use O_BINARY to match base file APIs.
-  return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
-              S_IRUSR | S_IWUSR);
-}
-
-char* mkdtemp(char* template_name) {
-  if (_mktemp(template_name) == nullptr) {
-    return nullptr;
-  }
-  if (_mkdir(template_name) == -1) {
-    return nullptr;
-  }
-  return template_name;
-}
-#endif
-
-static std::string GetSystemTempDir() {
-#if defined(__ANDROID__)
-  const char* tmpdir = "/data/local/tmp";
-  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
-    return tmpdir;
-  }
-  // Tests running in app context can't access /data/local/tmp,
-  // so try current directory if /data/local/tmp is not accessible.
-  return ".";
-#elif defined(_WIN32)
-  char tmp_dir[MAX_PATH];
-  DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
-  CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
-  CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
-
-  // GetTempPath() returns a path with a trailing slash, but init()
-  // does not expect that, so remove it.
-  CHECK_EQ(tmp_dir[result - 1], '\\');
-  tmp_dir[result - 1] = '\0';
-  return tmp_dir;
-#else
-  return "/tmp";
-#endif
-}
-
-TemporaryFile::TemporaryFile() {
-  init(GetSystemTempDir());
-}
-
-TemporaryFile::TemporaryFile(const std::string& tmp_dir) {
-  init(tmp_dir);
-}
-
-TemporaryFile::~TemporaryFile() {
-  if (fd != -1) {
-    close(fd);
-  }
-  if (remove_file_) {
-    unlink(path);
-  }
-}
-
-int TemporaryFile::release() {
-  int result = fd;
-  fd = -1;
-  return result;
-}
-
-void TemporaryFile::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
-           OS_PATH_SEPARATOR);
-  fd = mkstemp(path);
-}
-
-TemporaryDir::TemporaryDir() {
-  init(GetSystemTempDir());
-}
-
-TemporaryDir::~TemporaryDir() {
-  rmdir(path);
-}
-
-bool TemporaryDir::init(const std::string& tmp_dir) {
-  snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
-           OS_PATH_SEPARATOR);
-  return (mkdtemp(path) != nullptr);
-}
-
 CapturedStdFd::CapturedStdFd(int std_fd) : std_fd_(std_fd), old_fd_(-1) {
   Start();
 }
diff --git a/base/utf8_test.cpp b/base/utf8_test.cpp
index fcb25c3..472e82c 100644
--- a/base/utf8_test.cpp
+++ b/base/utf8_test.cpp
@@ -21,8 +21,8 @@
 #include <fcntl.h>
 #include <stdlib.h>
 
+#include "android-base/file.h"
 #include "android-base/macros.h"
-#include "android-base/test_utils.h"
 #include "android-base/unique_fd.h"
 
 namespace android {
diff --git a/bootstat/boot_event_record_store_test.cpp b/bootstat/boot_event_record_store_test.cpp
index 4b7ab36..5ca9b09 100644
--- a/bootstat/boot_event_record_store_test.cpp
+++ b/bootstat/boot_event_record_store_test.cpp
@@ -29,7 +29,6 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/test_utils.h>
 #include <android-base/unique_fd.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
diff --git a/debuggerd/libdebuggerd/test/open_files_list_test.cpp b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
index d7036fd..3e920eb 100644
--- a/debuggerd/libdebuggerd/test/open_files_list_test.cpp
+++ b/debuggerd/libdebuggerd/test/open_files_list_test.cpp
@@ -20,10 +20,9 @@
 
 #include <string>
 
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 
-#include "android-base/test_utils.h"
-
 #include "libdebuggerd/open_files_list.h"
 
 // Check that we can produce a list of open files for the current process, and
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 625e047..3e090d7 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -56,7 +56,6 @@
 #include <android-base/parsenetaddress.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android-base/test_utils.h>
 #include <android-base/unique_fd.h>
 #include <build/version.h>
 #include <platform_tools_version.h>
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index ed02c4a..f597f50 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -61,7 +61,7 @@
 
     UInt8 bulkIn;
     UInt8 bulkOut;
-    IOUSBInterfaceInterface190 **interface;
+    IOUSBInterfaceInterface500** interface;
     unsigned int zero_mask;
 };
 
@@ -86,13 +86,13 @@
 
 /** Try out all the interfaces and see if there's a match. Returns 0 on
  * success, -1 on failure. */
-static int try_interfaces(IOUSBDeviceInterface182 **dev, usb_handle *handle) {
+static int try_interfaces(IOUSBDeviceInterface500** dev, usb_handle* handle) {
     IOReturn kr;
     IOUSBFindInterfaceRequest request;
     io_iterator_t iterator;
     io_service_t usbInterface;
     IOCFPlugInInterface **plugInInterface;
-    IOUSBInterfaceInterface190 **interface = NULL;
+    IOUSBInterfaceInterface500** interface = NULL;
     HRESULT result;
     SInt32 score;
     UInt8 interfaceNumEndpoints;
@@ -128,10 +128,10 @@
         }
 
         // Now create the interface interface for the interface
-        result = (*plugInInterface)->QueryInterface(
-                plugInInterface,
-                CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
-                (LPVOID*) &interface);
+        result = (*plugInInterface)
+                         ->QueryInterface(plugInInterface,
+                                          CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID500),
+                                          (LPVOID*)&interface);
 
         // No longer need the intermediate plugin
         (*plugInInterface)->Release(plugInInterface);
@@ -270,7 +270,7 @@
 static int try_device(io_service_t device, usb_handle *handle) {
     kern_return_t kr;
     IOCFPlugInInterface **plugin = NULL;
-    IOUSBDeviceInterface182 **dev = NULL;
+    IOUSBDeviceInterface500** dev = NULL;
     SInt32 score;
     HRESULT result;
     UInt8 serialIndex;
@@ -287,8 +287,8 @@
     }
 
     // Now create the device interface.
-    result = (*plugin)->QueryInterface(plugin,
-            CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
+    result = (*plugin)->QueryInterface(plugin, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID500),
+                                       (LPVOID*)&dev);
     if ((result != 0) || (dev == NULL)) {
         ERR("Couldn't create a device interface (%08x)\n", (int) result);
         goto error;
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/fs_mgr_avb.cpp
index 7c6093e..31affbe 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/fs_mgr_avb.cpp
@@ -322,17 +322,6 @@
             continue;
         }
 
-        // Ensures that hashtree descriptor is in /vbmeta or /boot or in
-        // the same partition for verity setup.
-        std::string vbmeta_partition_name(verify_data.vbmeta_images[i].partition_name);
-        if (vbmeta_partition_name != "vbmeta" &&
-            vbmeta_partition_name != "boot" &&  // for legacy device to append top-level vbmeta
-            vbmeta_partition_name != partition_name) {
-            LWARNING << "Skip vbmeta image at " << verify_data.vbmeta_images[i].partition_name
-                     << " for partition: " << partition_name.c_str();
-            continue;
-        }
-
         for (size_t j = 0; j < num_descriptors && !found; j++) {
             AvbDescriptor desc;
             if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 49ecc06..a1de005 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <sys/vfs.h>
 #include <unistd.h>
 
@@ -56,13 +57,17 @@
 using namespace android::dm;
 using namespace android::fs_mgr;
 
-static bool fs_mgr_access(const std::string& path) {
+namespace {
+
+bool fs_mgr_access(const std::string& path) {
     auto save_errno = errno;
     auto ret = access(path.c_str(), F_OK) == 0;
     errno = save_errno;
     return ret;
 }
 
+}  // namespace
+
 #if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs
 
 bool fs_mgr_overlayfs_mount_all(fstab*) {
@@ -218,9 +223,12 @@
 std::string fs_mgr_get_overlayfs_options(const std::string& mount_point) {
     auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
     if (candidate.empty()) return "";
-
-    return "override_creds=off," + kLowerdirOption + mount_point + "," + kUpperdirOption +
-           candidate + kUpperName + ",workdir=" + candidate + kWorkName;
+    auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName +
+               ",workdir=" + candidate + kWorkName;
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
+        ret += ",override_creds=off";
+    }
+    return ret;
 }
 
 const char* fs_mgr_mount_point(const char* mount_point) {
@@ -733,7 +741,7 @@
 bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
     auto ret = false;
 
-    if (!fs_mgr_overlayfs_supports_override_creds()) return ret;
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
 
     if (!fstab) return ret;
 
@@ -791,7 +799,7 @@
 bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
     if (change) *change = false;
     auto ret = false;
-    if (!fs_mgr_overlayfs_supports_override_creds()) return ret;
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
     if (!fs_mgr_boot_completed()) {
         errno = EBUSY;
         PERROR << "setup";
@@ -854,7 +862,7 @@
     for (const auto& overlay_mount_point : kOverlayMountPoints) {
         ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change);
     }
-    if (!fs_mgr_overlayfs_supports_override_creds()) {
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
         // After obligatory teardown to make sure everything is clean, but if
         // we didn't want overlayfs in the the first place, we do not want to
         // waste time on a reboot (or reboot request message).
@@ -905,7 +913,30 @@
     return context;
 }
 
-bool fs_mgr_overlayfs_supports_override_creds() {
+OverlayfsValidResult fs_mgr_overlayfs_valid() {
     // Overlayfs available in the kernel, and patched for override_creds?
-    return fs_mgr_access("/sys/module/overlay/parameters/override_creds");
+    if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
+        return OverlayfsValidResult::kOverrideCredsRequired;
+    }
+    if (!fs_mgr_access("/sys/module/overlay")) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    struct utsname uts;
+    if (uname(&uts) == -1) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    int major, minor;
+    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    if (major < 4) {
+        return OverlayfsValidResult::kOk;
+    }
+    if (major > 4) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    if (minor > 6) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    return OverlayfsValidResult::kOk;
 }
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index a9a69cd..e1815ff 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -87,8 +87,10 @@
         return false;
     }
 
-    auto options =
-            "override_creds=off,"s + kLowerdirOption + source_directory + ":" + vendor_mount_point;
+    auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point;
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
+        options += ",override_creds=off";
+    }
     auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
                   options + ")=";
     auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
@@ -117,7 +119,7 @@
     }
     const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
     if (vendor_overlay_dirs.empty()) return true;
-    if (!fs_mgr_overlayfs_supports_override_creds()) {
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
         LINFO << "vendor overlay: kernel does not support overlayfs";
         return false;
     }
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 72202ab..deaf4cb 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -31,4 +31,10 @@
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
 bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
 std::string fs_mgr_get_context(const std::string& mount_point);
-bool fs_mgr_overlayfs_supports_override_creds();
+
+enum class OverlayfsValidResult {
+    kNotSupported = 0,
+    kOk,
+    kOverrideCredsRequired,
+};
+OverlayfsValidResult fs_mgr_overlayfs_valid();
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4007ad9..b6d6da1 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -113,18 +113,7 @@
     if (!metadata) {
         return nullptr;
     }
-    std::unique_ptr<MetadataBuilder> builder = New(*metadata.get());
-    if (!builder) {
-        return nullptr;
-    }
-    for (size_t i = 0; i < builder->block_devices_.size(); i++) {
-        std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
-        BlockDeviceInfo device_info;
-        if (opener.GetInfo(partition_name, &device_info)) {
-            builder->UpdateBlockDeviceInfo(i, device_info);
-        }
-    }
-    return builder;
+    return New(*metadata.get(), &opener);
 }
 
 std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_partition,
@@ -142,15 +131,70 @@
     return builder;
 }
 
-std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata) {
+std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const LpMetadata& metadata,
+                                                      const IPartitionOpener* opener) {
     std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
     if (!builder->Init(metadata)) {
         return nullptr;
     }
+    if (opener) {
+        for (size_t i = 0; i < builder->block_devices_.size(); i++) {
+            std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
+            BlockDeviceInfo device_info;
+            if (opener->GetInfo(partition_name, &device_info)) {
+                builder->UpdateBlockDeviceInfo(i, device_info);
+            }
+        }
+    }
     return builder;
 }
 
-MetadataBuilder::MetadataBuilder() {
+std::unique_ptr<MetadataBuilder> MetadataBuilder::NewForUpdate(const IPartitionOpener& opener,
+                                                               const std::string& source_partition,
+                                                               uint32_t source_slot_number,
+                                                               uint32_t target_slot_number) {
+    auto metadata = ReadMetadata(opener, source_partition, source_slot_number);
+    if (!metadata) {
+        return nullptr;
+    }
+
+    // Get the list of devices we already have.
+    std::set<std::string> block_devices;
+    for (const auto& block_device : metadata->block_devices) {
+        block_devices.emplace(GetBlockDevicePartitionName(block_device));
+    }
+
+    auto new_block_devices = metadata->block_devices;
+
+    // Add missing block devices.
+    std::string source_slot_suffix = SlotSuffixForSlotNumber(source_slot_number);
+    std::string target_slot_suffix = SlotSuffixForSlotNumber(target_slot_number);
+    for (const auto& block_device : metadata->block_devices) {
+        std::string partition_name = GetBlockDevicePartitionName(block_device);
+        std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
+        if (slot_suffix.empty() || slot_suffix != source_slot_suffix) {
+            continue;
+        }
+        std::string new_name =
+                partition_name.substr(0, partition_name.size() - slot_suffix.size()) +
+                target_slot_suffix;
+        if (block_devices.find(new_name) != block_devices.end()) {
+            continue;
+        }
+
+        auto new_device = block_device;
+        if (!UpdateBlockDevicePartitionName(&new_device, new_name)) {
+            LERROR << "Partition name too long: " << new_name;
+            return nullptr;
+        }
+        new_block_devices.emplace_back(new_device);
+    }
+
+    metadata->block_devices = new_block_devices;
+    return New(*metadata.get(), &opener);
+}
+
+MetadataBuilder::MetadataBuilder() : auto_slot_suffixing_(false) {
     memset(&geometry_, 0, sizeof(geometry_));
     geometry_.magic = LP_METADATA_GEOMETRY_MAGIC;
     geometry_.struct_size = sizeof(geometry_);
@@ -492,8 +536,8 @@
         if (group_size >= group->maximum_size() ||
             group->maximum_size() - group_size < space_needed) {
             LERROR << "Partition " << partition->name() << " is part of group " << group->name()
-                   << " which does not have enough space free (" << space_needed << "requested, "
-                   << group_size << " used out of " << group->maximum_size();
+                   << " which does not have enough space free (" << space_needed << " requested, "
+                   << group_size << " used out of " << group->maximum_size() << ")";
             return false;
         }
     }
@@ -564,7 +608,12 @@
     metadata->geometry = geometry_;
 
     // Assign this early so the extent table can read it.
-    metadata->block_devices = block_devices_;
+    for (const auto& block_device : block_devices_) {
+        metadata->block_devices.emplace_back(block_device);
+        if (auto_slot_suffixing_) {
+            metadata->block_devices.back().flags |= LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+        }
+    }
 
     std::map<std::string, size_t> group_indices;
     for (const auto& group : groups_) {
@@ -600,6 +649,9 @@
         part.first_extent_index = static_cast<uint32_t>(metadata->extents.size());
         part.num_extents = static_cast<uint32_t>(partition->extents().size());
         part.attributes = partition->attributes();
+        if (auto_slot_suffixing_) {
+            part.attributes |= LP_PARTITION_ATTR_SLOT_SUFFIXED;
+        }
 
         auto iter = group_indices.find(partition->group_name());
         if (iter == group_indices.end()) {
@@ -836,5 +888,9 @@
     return true;
 }
 
+void MetadataBuilder::SetAutoSlotSuffixing() {
+    auto_slot_suffixing_ = true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 46bdfa4..9e64de1 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -62,7 +62,7 @@
 }
 
 std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
-    android::base::unique_fd fd(open(file, O_RDONLY));
+    android::base::unique_fd fd(open(file, O_RDONLY | O_CLOEXEC));
     if (fd < 0) {
         PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
         return nullptr;
@@ -84,7 +84,7 @@
 }
 
 bool WriteToImageFile(const char* file, const LpMetadata& input) {
-    android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+    android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
     if (fd < 0) {
         PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
         return false;
@@ -97,7 +97,6 @@
     : metadata_(metadata),
       geometry_(metadata.geometry),
       block_size_(block_size),
-      file_(nullptr, sparse_file_destroy),
       images_(images) {
     uint64_t total_size = GetTotalSuperPartitionSize(metadata);
     if (block_size % LP_SECTOR_SIZE != 0) {
@@ -121,7 +120,7 @@
         return;
     }
 
-    uint64_t num_blocks = total_size % block_size;
+    uint64_t num_blocks = total_size / block_size;
     if (num_blocks >= UINT_MAX) {
         // libsparse counts blocks in unsigned 32-bit integers, so we check to
         // make sure we're not going to overflow.
@@ -129,20 +128,32 @@
         return;
     }
 
-    file_.reset(sparse_file_new(block_size_, total_size));
-    if (!file_) {
-        LERROR << "Could not allocate sparse file of size " << total_size;
+    for (const auto& block_device : metadata.block_devices) {
+        SparsePtr file(sparse_file_new(block_size_, block_device.size), sparse_file_destroy);
+        if (!file) {
+            LERROR << "Could not allocate sparse file of size " << block_device.size;
+            return;
+        }
+        device_images_.emplace_back(std::move(file));
     }
 }
 
+bool SparseBuilder::IsValid() const {
+    return device_images_.size() == metadata_.block_devices.size();
+}
+
 bool SparseBuilder::Export(const char* file) {
-    android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
+    android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
     if (fd < 0) {
         PERROR << "open failed: " << file;
         return false;
     }
+    if (device_images_.size() > 1) {
+        LERROR << "Cannot export to a single image on retrofit builds.";
+        return false;
+    }
     // No gzip compression; sparseify; no checksum.
-    int ret = sparse_file_write(file_.get(), fd, false, true, false);
+    int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false);
     if (ret != 0) {
         LERROR << "sparse_file_write failed (error code " << ret << ")";
         return false;
@@ -150,13 +161,39 @@
     return true;
 }
 
-bool SparseBuilder::AddData(const std::string& blob, uint64_t sector) {
+bool SparseBuilder::ExportFiles(const std::string& output_dir) {
+    android::base::unique_fd dir(open(output_dir.c_str(), O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW));
+    if (dir < 0) {
+        PERROR << "open dir failed: " << output_dir;
+        return false;
+    }
+
+    for (size_t i = 0; i < device_images_.size(); i++) {
+        std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
+        std::string path = output_dir + "/super_" + name + ".img";
+        android::base::unique_fd fd(openat(
+                dir, path.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, 0644));
+        if (fd < 0) {
+            PERROR << "open failed: " << path;
+            return false;
+        }
+        // No gzip compression; sparseify; no checksum.
+        int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false);
+        if (ret != 0) {
+            LERROR << "sparse_file_write failed (error code " << ret << ")";
+            return false;
+        }
+    }
+    return true;
+}
+
+bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
     uint32_t block;
     if (!SectorToBlock(sector, &block)) {
         return false;
     }
     void* data = const_cast<char*>(blob.data());
-    int ret = sparse_file_add_data(file_.get(), data, blob.size(), block);
+    int ret = sparse_file_add_data(file, data, blob.size(), block);
     if (ret != 0) {
         LERROR << "sparse_file_add_data failed (error code " << ret << ")";
         return false;
@@ -179,8 +216,12 @@
     return true;
 }
 
+uint64_t SparseBuilder::BlockToSector(uint64_t block) const {
+    return (block * block_size_) / LP_SECTOR_SIZE;
+}
+
 bool SparseBuilder::Build() {
-    if (sparse_file_add_fill(file_.get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
+    if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
         LERROR << "Could not add initial sparse block for reserved zeroes";
         return false;
     }
@@ -194,7 +235,13 @@
     for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
         all_metadata_ += metadata_blob;
     }
-    if (!AddData(all_metadata_, 0)) {
+
+    uint64_t first_sector = LP_PARTITION_RESERVED_BYTES / LP_SECTOR_SIZE;
+    if (!AddData(device_images_[0].get(), all_metadata_, first_sector)) {
+        return false;
+    }
+
+    if (!CheckExtentOrdering()) {
         return false;
     }
 
@@ -228,13 +275,10 @@
 
 bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
                                       const std::string& file) {
-    if (partition.num_extents != 1) {
-        LERROR << "Partition for new tables should not have more than one extent: "
-               << GetPartitionName(partition);
-        return false;
-    }
+    // Track which extent we're processing.
+    uint32_t extent_index = partition.first_extent_index;
 
-    const LpMetadataExtent& extent = metadata_.extents[partition.first_extent_index];
+    const LpMetadataExtent& extent = metadata_.extents[extent_index];
     if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
         LERROR << "Partition should only have linear extents: " << GetPartitionName(partition);
         return false;
@@ -252,9 +296,11 @@
         LERROR << "Could not compute image size";
         return false;
     }
-    if (file_length > extent.num_sectors * LP_SECTOR_SIZE) {
+    uint64_t partition_size = ComputePartitionSize(partition);
+    if (file_length > partition_size) {
         LERROR << "Image for partition '" << GetPartitionName(partition)
-               << "' is greater than its size";
+               << "' is greater than its size (" << file_length << ", expected " << partition_size
+               << ")";
         return false;
     }
     if (SeekFile64(fd, 0, SEEK_SET)) {
@@ -262,14 +308,39 @@
         return false;
     }
 
+    // We track the current logical sector and the position the current extent
+    // ends at.
+    uint64_t output_sector = 0;
+    uint64_t extent_last_sector = extent.num_sectors;
+
+    // We also track the output device and the current output block within that
+    // device.
     uint32_t output_block;
     if (!SectorToBlock(extent.target_data, &output_block)) {
         return false;
     }
+    sparse_file* output_device = device_images_[extent.target_source].get();
 
+    // Proceed to read the file and build sparse images.
     uint64_t pos = 0;
     uint64_t remaining = file_length;
     while (remaining) {
+        // Check if we need to advance to the next extent.
+        if (output_sector == extent_last_sector) {
+            extent_index++;
+            if (extent_index >= partition.first_extent_index + partition.num_extents) {
+                LERROR << "image is larger than extent table";
+                return false;
+            }
+
+            const LpMetadataExtent& extent = metadata_.extents[extent_index];
+            extent_last_sector += extent.num_sectors;
+            output_device = device_images_[extent.target_source].get();
+            if (!SectorToBlock(extent.target_data, &output_block)) {
+                return false;
+            }
+        }
+
         uint32_t buffer[block_size_ / sizeof(uint32_t)];
         size_t read_size = remaining >= sizeof(buffer) ? sizeof(buffer) : size_t(remaining);
         if (!android::base::ReadFully(fd, buffer, sizeof(buffer))) {
@@ -277,13 +348,13 @@
             return false;
         }
         if (read_size != sizeof(buffer) || !HasFillValue(buffer, read_size / sizeof(uint32_t))) {
-            int rv = sparse_file_add_fd(file_.get(), fd, pos, read_size, output_block);
+            int rv = sparse_file_add_fd(output_device, fd, pos, read_size, output_block);
             if (rv) {
                 LERROR << "sparse_file_add_fd failed with code: " << rv;
                 return false;
             }
         } else {
-            int rv = sparse_file_add_fill(file_.get(), buffer[0], read_size, output_block);
+            int rv = sparse_file_add_fill(output_device, buffer[0], read_size, output_block);
             if (rv) {
                 LERROR << "sparse_file_add_fill failed with code: " << rv;
                 return false;
@@ -291,46 +362,76 @@
         }
         pos += read_size;
         remaining -= read_size;
+        output_sector += block_size_ / LP_SECTOR_SIZE;
         output_block++;
     }
 
     return true;
 }
 
+uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
+    uint64_t sectors = 0;
+    for (size_t i = 0; i < partition.num_extents; i++) {
+        sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
+    }
+    return sectors * LP_SECTOR_SIZE;
+}
+
+// For simplicity, we don't allow serializing any configuration: extents must
+// be ordered, such that any extent at position I in the table occurs *before*
+// any extent after position I, for the same block device. We validate that
+// here.
+//
+// Without this, it would be more difficult to find the appropriate extent for
+// an output block. With this guarantee it is a linear walk.
+bool SparseBuilder::CheckExtentOrdering() {
+    std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
+
+    for (const auto& extent : metadata_.extents) {
+        if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
+            LERROR << "Extents must all be type linear.";
+            return false;
+        }
+        if (extent.target_data <= last_sectors[extent.target_source]) {
+            LERROR << "Extents must appear in increasing order.";
+            return false;
+        }
+        if ((extent.num_sectors * LP_SECTOR_SIZE) % block_size_ != 0) {
+            LERROR << "Extents must be aligned to the block size.";
+            return false;
+        }
+        last_sectors[extent.target_source] = extent.target_data;
+    }
+    return true;
+}
+
 int SparseBuilder::OpenImageFile(const std::string& file) {
-    android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY));
+    android::base::unique_fd source_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
     if (source_fd < 0) {
         PERROR << "open image file failed: " << file;
         return -1;
     }
 
-    std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> source(
-            sparse_file_import(source_fd, true, true), sparse_file_destroy);
+    SparsePtr source(sparse_file_import(source_fd, true, true), sparse_file_destroy);
     if (!source) {
         int fd = source_fd.get();
         temp_fds_.push_back(std::move(source_fd));
         return fd;
     }
 
-    char temp_file[PATH_MAX];
-    snprintf(temp_file, sizeof(temp_file), "%s/imageXXXXXX", P_tmpdir);
-    android::base::unique_fd temp_fd(mkstemp(temp_file));
-    if (temp_fd < 0) {
-        PERROR << "mkstemp failed";
-        return -1;
-    }
-    if (unlink(temp_file) < 0) {
-        PERROR << "unlink failed";
+    TemporaryFile tf;
+    if (tf.fd < 0) {
+        PERROR << "make temporary file failed";
         return -1;
     }
 
     // We temporarily unsparse the file, rather than try to merge its chunks.
-    int rv = sparse_file_write(source.get(), temp_fd, false, false, false);
+    int rv = sparse_file_write(source.get(), tf.fd, false, false, false);
     if (rv) {
         LERROR << "sparse_file_write failed with code: " << rv;
         return -1;
     }
-    temp_fds_.push_back(std::move(temp_fd));
+    temp_fds_.push_back(android::base::unique_fd(tf.release()));
     return temp_fds_.back().get();
 }
 
@@ -340,5 +441,11 @@
     return builder.IsValid() && builder.Build() && builder.Export(file);
 }
 
+bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
+                           uint32_t block_size, const std::map<std::string, std::string>& images) {
+    SparseBuilder builder(metadata, block_size, images);
+    return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index a9ef8ce..44217a0 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -42,20 +42,26 @@
 
     bool Build();
     bool Export(const char* file);
-    bool IsValid() const { return file_ != nullptr; }
+    bool ExportFiles(const std::string& dir);
+    bool IsValid() const;
 
-    sparse_file* file() const { return file_.get(); }
+    using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
+    const std::vector<SparsePtr>& device_images() const { return device_images_; }
 
   private:
-    bool AddData(const std::string& blob, uint64_t sector);
+    bool AddData(sparse_file* file, const std::string& blob, uint64_t sector);
     bool AddPartitionImage(const LpMetadataPartition& partition, const std::string& file);
     int OpenImageFile(const std::string& file);
     bool SectorToBlock(uint64_t sector, uint32_t* block);
+    uint64_t BlockToSector(uint64_t block) const;
+    bool CheckExtentOrdering();
+    uint64_t ComputePartitionSize(const LpMetadataPartition& partition) const;
 
     const LpMetadata& metadata_;
     const LpMetadataGeometry& geometry_;
     uint32_t block_size_;
-    std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
+
+    std::vector<SparsePtr> device_images_;
     std::string all_metadata_;
     std::map<std::string, std::string> images_;
     std::vector<android::base::unique_fd> temp_fds_;
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index d5e3fed..59717d1 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -150,10 +150,24 @@
     static std::unique_ptr<MetadataBuilder> New(const std::string& super_partition,
                                                 uint32_t slot_number);
 
+    // This is when performing an A/B update. The source partition must be a
+    // super partition. On a normal device, the metadata for the source slot
+    // is imported and the target slot is ignored. On a retrofit device, the
+    // metadata may not have the target slot's devices listed yet, in which
+    // case, it is automatically upgraded to include all available block
+    // devices.
+    static std::unique_ptr<MetadataBuilder> NewForUpdate(const IPartitionOpener& opener,
+                                                         const std::string& source_partition,
+                                                         uint32_t source_slot_number,
+                                                         uint32_t target_slot_number);
+
     // Import an existing table for modification. If the table is not valid, for
     // example it contains duplicate partition names, then nullptr is returned.
-    // This method is for testing or changing off-line tables.
-    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
+    //
+    // If an IPartitionOpener is specified, then block device informatiom will
+    // be updated.
+    static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata,
+                                                const IPartitionOpener* opener = nullptr);
 
     // Helper function for a single super partition, for tests.
     static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
@@ -223,6 +237,9 @@
     // Remove all partitions belonging to a group, then remove the group.
     void RemoveGroupAndPartitions(const std::string& group_name);
 
+    // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
+    void SetAutoSlotSuffixing();
+
     bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
     bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
 
@@ -275,6 +292,7 @@
     std::vector<std::unique_ptr<Partition>> partitions_;
     std::vector<std::unique_ptr<PartitionGroup>> groups_;
     std::vector<LpMetadataBlockDevice> block_devices_;
+    bool auto_slot_suffixing_;
 };
 
 // Read BlockDeviceInfo for a given block device. This always returns false
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 8723a7f..1af1e80 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -78,6 +78,14 @@
 std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file);
 std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
 
+// Similar to WriteToSparseFile, this will generate an image that can be
+// flashed to a device directly. However unlike WriteToSparseFile, it
+// is intended for retrofit devices, and will generate one sparse file per
+// block device (each named super_<name>.img) and placed in the specified
+// output folder.
+bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
+                           uint32_t block_size, const std::map<std::string, std::string>& images);
+
 // Helper to extract safe C++ strings from partition info.
 std::string GetPartitionName(const LpMetadataPartition& partition);
 std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
@@ -95,6 +103,7 @@
 
 // Slot suffix helpers.
 uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
+std::string SlotSuffixForSlotNumber(uint32_t slot_number);
 std::string GetPartitionSlotSuffix(const std::string& partition_name);
 
 }  // namespace fs_mgr
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 1e40df3..c2e25fb 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
 #define LP_METADATA_HEADER_MAGIC 0x414C5030
 
 /* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 8
+#define LP_METADATA_MAJOR_VERSION 9
 #define LP_METADATA_MINOR_VERSION 0
 
 /* Attributes for the LpMetadataPartition::attributes field.
@@ -47,10 +47,19 @@
  * device mapper, the block device will be created as read-only.
  */
 #define LP_PARTITION_ATTR_NONE 0x0
-#define LP_PARTITION_ATTR_READONLY 0x1
+#define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+#define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
 
 /* Mask that defines all valid attributes. */
-#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY)
+#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
 
 /* Default name of the physical partition that holds logical partition entries.
  * The layout of this partition will look like:
@@ -302,8 +311,21 @@
 
     /* 24: Partition name in the GPT. Any unused characters must be 0. */
     char partition_name[36];
+
+    /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+    uint32_t flags;
 } LpMetadataBlockDevice;
 
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+#define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 603e5c0..9acf23e 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -38,6 +38,7 @@
 static const size_t kDiskSize = 131072;
 static const size_t kMetadataSize = 512;
 static const size_t kMetadataSlots = 2;
+static const BlockDeviceInfo kSuperInfo{"super", kDiskSize, 0, 0, 4096};
 
 // Helper function for creating an in-memory file descriptor. This lets us
 // simulate read/writing logical partition metadata as if we had a block device
@@ -79,6 +80,12 @@
     return builder;
 }
 
+class DefaultPartitionOpener final : public TestPartitionOpener {
+  public:
+    explicit DefaultPartitionOpener(int fd)
+        : TestPartitionOpener({{"super", fd}}, {{"super", kSuperInfo}}) {}
+};
+
 static bool AddDefaultPartitions(MetadataBuilder* builder) {
     Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_NONE);
     if (!system) {
@@ -103,7 +110,7 @@
         return {};
     }
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
     if (!FlashPartitionTable(opener, "super", *exported.get())) {
         return {};
     }
@@ -119,7 +126,7 @@
     ASSERT_TRUE(GetDescriptorSize(fd, &size));
     ASSERT_EQ(size, kDiskSize);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     // Verify that we can't read unwritten metadata.
     ASSERT_EQ(ReadMetadata(opener, "super", 1), nullptr);
@@ -138,7 +145,7 @@
     unique_fd fd = CreateFakeDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     EXPECT_FALSE(FlashPartitionTable(opener, "super", *exported.get()));
 }
@@ -152,7 +159,7 @@
     unique_fd fd = CreateFakeDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     // Export and flash.
     unique_ptr<LpMetadata> exported = builder->Export();
@@ -198,7 +205,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
     ASSERT_NE(imported, nullptr);
@@ -243,7 +250,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     // Make sure all slots are filled.
     unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
@@ -262,7 +269,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     unique_ptr<LpMetadata> imported = ReadMetadata(opener, "super", 0);
     ASSERT_NE(imported, nullptr);
@@ -291,7 +298,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     LpMetadataGeometry geometry;
     ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
@@ -310,7 +317,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     char corruption[LP_METADATA_GEOMETRY_SIZE];
     memset(corruption, 0xff, sizeof(corruption));
@@ -330,7 +337,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     unique_ptr<LpMetadata> metadata = ReadMetadata(opener, "super", 0);
 
@@ -378,7 +385,7 @@
     unique_fd fd = CreateFakeDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     // Check that we are able to write our table.
     ASSERT_TRUE(FlashPartitionTable(opener, "super", *exported.get()));
@@ -487,7 +494,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     BadWriter writer;
 
@@ -515,7 +522,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     BadWriter writer;
 
@@ -544,7 +551,7 @@
     unique_fd fd = CreateFlashedDisk();
     ASSERT_GE(fd, 0);
 
-    TestPartitionOpener opener({{"super", fd}});
+    DefaultPartitionOpener opener(fd);
 
     BadWriter writer;
 
@@ -593,12 +600,14 @@
     // Build the sparse file.
     SparseBuilder sparse(*exported.get(), 512, {});
     ASSERT_TRUE(sparse.IsValid());
-    sparse_file_verbose(sparse.file());
     ASSERT_TRUE(sparse.Build());
 
+    const auto& images = sparse.device_images();
+    ASSERT_EQ(images.size(), static_cast<size_t>(1));
+
     // Write it to the fake disk.
     ASSERT_NE(lseek(fd.get(), 0, SEEK_SET), -1);
-    int ret = sparse_file_write(sparse.file(), fd.get(), false, false, false);
+    int ret = sparse_file_write(images[0].get(), fd.get(), false, false, false);
     ASSERT_EQ(ret, 0);
 
     // Verify that we can read both sets of metadata.
@@ -608,3 +617,74 @@
     ASSERT_NE(ReadPrimaryMetadata(fd.get(), geometry, 0), nullptr);
     ASSERT_NE(ReadBackupMetadata(fd.get(), geometry, 0), nullptr);
 }
+
+TEST(liblp, AutoSlotSuffixing) {
+    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
+    ASSERT_NE(builder, nullptr);
+    ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+    builder->SetAutoSlotSuffixing();
+
+    auto fd = CreateFakeDisk();
+    ASSERT_GE(fd, 0);
+
+    // Note: we bind the same fd to both names, since we want to make sure the
+    // exact same bits are getting read back in each test.
+    TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
+                               {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
+    auto exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
+
+    auto metadata = ReadMetadata(opener, "super_b", 1);
+    ASSERT_NE(metadata, nullptr);
+    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_b");
+    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_b");
+
+    metadata = ReadMetadata(opener, "super_a", 0);
+    ASSERT_NE(metadata, nullptr);
+    ASSERT_EQ(metadata->partitions.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetPartitionName(metadata->partitions[0]), "system_a");
+    ASSERT_EQ(metadata->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "super_a");
+}
+
+TEST(liblp, UpdateRetrofit) {
+    unique_ptr<MetadataBuilder> builder = CreateDefaultBuilder();
+    ASSERT_NE(builder, nullptr);
+    ASSERT_TRUE(AddDefaultPartitions(builder.get()));
+    builder->SetAutoSlotSuffixing();
+
+    auto fd = CreateFakeDisk();
+    ASSERT_GE(fd, 0);
+
+    // Note: we bind the same fd to both names, since we want to make sure the
+    // exact same bits are getting read back in each test.
+    TestPartitionOpener opener({{"super_a", fd}, {"super_b", fd}},
+                               {{"super_a", kSuperInfo}, {"super_b", kSuperInfo}});
+    auto exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    ASSERT_TRUE(FlashPartitionTable(opener, "super_a", *exported.get()));
+
+    builder = MetadataBuilder::NewForUpdate(opener, "super_a", 0, 1);
+    ASSERT_NE(builder, nullptr);
+    auto updated = builder->Export();
+    ASSERT_NE(updated, nullptr);
+    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(2));
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super_a");
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[1]), "super_b");
+}
+
+TEST(liblp, UpdateNonRetrofit) {
+    unique_fd fd = CreateFlashedDisk();
+    ASSERT_GE(fd, 0);
+
+    DefaultPartitionOpener opener(fd);
+    auto builder = MetadataBuilder::NewForUpdate(opener, "super", 0, 1);
+    ASSERT_NE(builder, nullptr);
+    auto updated = builder->Export();
+    ASSERT_NE(updated, nullptr);
+    ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
+    EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
+}
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index a02e746..b36ba0e 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -348,6 +348,38 @@
     return ParseMetadata(geometry, fd);
 }
 
+namespace {
+
+bool AdjustMetadataForSlot(LpMetadata* metadata, uint32_t slot_number) {
+    std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+    for (auto& partition : metadata->partitions) {
+        if (!(partition.attributes & LP_PARTITION_ATTR_SLOT_SUFFIXED)) {
+            continue;
+        }
+        std::string partition_name = GetPartitionName(partition) + slot_suffix;
+        if (partition_name.size() > sizeof(partition.name)) {
+            LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+            return false;
+        }
+        strncpy(partition.name, partition_name.c_str(), sizeof(partition.name));
+        partition.attributes &= ~LP_PARTITION_ATTR_SLOT_SUFFIXED;
+    }
+    for (auto& block_device : metadata->block_devices) {
+        if (!(block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED)) {
+            continue;
+        }
+        std::string partition_name = GetBlockDevicePartitionName(block_device) + slot_suffix;
+        if (!UpdateBlockDevicePartitionName(&block_device, partition_name)) {
+            LERROR << __PRETTY_FUNCTION__ << " partition name too long: " << partition_name;
+            return false;
+        }
+        block_device.flags &= ~LP_BLOCK_DEVICE_SLOT_SUFFIXED;
+    }
+    return true;
+}
+
+}  // namespace
+
 std::unique_ptr<LpMetadata> ReadMetadata(const IPartitionOpener& opener,
                                          const std::string& super_partition, uint32_t slot_number) {
     android::base::unique_fd fd = opener.Open(super_partition, O_RDONLY);
@@ -360,18 +392,30 @@
     if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
         return nullptr;
     }
-
     if (slot_number >= geometry.metadata_slot_count) {
         LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
         return nullptr;
     }
 
-    // Read the primary copy, and if that fails, try the backup.
-    std::unique_ptr<LpMetadata> metadata = ReadPrimaryMetadata(fd, geometry, slot_number);
-    if (metadata) {
-        return metadata;
+    std::vector<int64_t> offsets = {
+            GetPrimaryMetadataOffset(geometry, slot_number),
+            GetBackupMetadataOffset(geometry, slot_number),
+    };
+    std::unique_ptr<LpMetadata> metadata;
+
+    for (const auto& offset : offsets) {
+        if (SeekFile64(fd, offset, SEEK_SET) < 0) {
+            PERROR << __PRETTY_FUNCTION__ << " lseek failed, offset " << offset;
+            continue;
+        }
+        if ((metadata = ParseMetadata(geometry, fd)) != nullptr) {
+            break;
+        }
     }
-    return ReadBackupMetadata(fd, geometry, slot_number);
+    if (!metadata || !AdjustMetadataForSlot(metadata.get(), slot_number)) {
+        return nullptr;
+    }
+    return metadata;
 }
 
 std::unique_ptr<LpMetadata> ReadMetadata(const std::string& super_partition, uint32_t slot_number) {
diff --git a/fs_mgr/liblp/reader.h b/fs_mgr/liblp/reader.h
index d5d5188..7a2490b 100644
--- a/fs_mgr/liblp/reader.h
+++ b/fs_mgr/liblp/reader.h
@@ -38,7 +38,9 @@
 bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry);
 bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry);
 
-// These functions assume a valid geometry and slot number.
+// These functions assume a valid geometry and slot number, and do not obey
+// auto-slot-suffixing. They are used for tests and for checking whether
+// the metadata is coherent across primary and backup copies.
 std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry& geometry,
                                                 uint32_t slot_number);
 std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index cce90a3..4f20b6b 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -132,5 +132,18 @@
     return (suffix == "_a" || suffix == "_b") ? suffix : "";
 }
 
+std::string SlotSuffixForSlotNumber(uint32_t slot_number) {
+    CHECK(slot_number == 0 || slot_number == 1);
+    return (slot_number == 0) ? "_a" : "_b";
+}
+
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name) {
+    if (name.size() > sizeof(device->partition_name)) {
+        return false;
+    }
+    strncpy(device->partition_name, name.c_str(), sizeof(device->partition_name));
+    return true;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h
index 65e643b..55ecb5a 100644
--- a/fs_mgr/liblp/utility.h
+++ b/fs_mgr/liblp/utility.h
@@ -84,6 +84,9 @@
     return aligned;
 }
 
+// Update names from C++ strings.
+bool UpdateBlockDevicePartitionName(LpMetadataBlockDevice* device, const std::string& name);
+
 }  // namespace fs_mgr
 }  // namespace android
 
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 0fa4590..15f7fff 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -32,6 +32,11 @@
     EXPECT_EQ(SlotNumberForSlotSuffix("_d"), 0);
 }
 
+TEST(liblp, SlotSuffixForSlotNumber) {
+    EXPECT_EQ(SlotSuffixForSlotNumber(0), "_a");
+    EXPECT_EQ(SlotSuffixForSlotNumber(1), "_b");
+}
+
 TEST(liblp, GetMetadataOffset) {
     LpMetadataGeometry geometry = {LP_METADATA_GEOMETRY_MAGIC,
                                    sizeof(geometry),
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index f4c9b99..e72cdfa 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -83,7 +83,7 @@
 // Perform sanity checks so we don't accidentally overwrite valid metadata
 // with potentially invalid metadata, or random partition data with metadata.
 static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
-                                         std::string* blob) {
+                                         const std::string& slot_suffix, std::string* blob) {
     const LpMetadataHeader& header = metadata.header;
     const LpMetadataGeometry& geometry = metadata.geometry;
 
@@ -114,6 +114,15 @@
     }
     for (const auto& block_device : metadata.block_devices) {
         std::string partition_name = GetBlockDevicePartitionName(block_device);
+        if (block_device.flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) {
+            if (slot_suffix.empty()) {
+                LERROR << "Block device " << partition_name << " requires a slot suffix,"
+                       << " which could not be derived from the super partition name.";
+                return false;
+            }
+            partition_name += slot_suffix;
+        }
+
         if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
             LERROR << "Block device " << partition_name << " has invalid first sector "
                    << block_device.first_logical_sector << " for size " << block_device.size;
@@ -234,11 +243,16 @@
         return false;
     }
 
+    // This is only used in update_engine and fastbootd, where the super
+    // partition should be specified as a name (or by-name link), and
+    // therefore, we should be able to extract a slot suffix.
+    std::string slot_suffix = GetPartitionSlotSuffix(super_partition);
+
     // Before writing geometry and/or logical partition tables, perform some
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string metadata_blob;
-    if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &metadata_blob)) {
         return false;
     }
 
@@ -299,11 +313,13 @@
         return false;
     }
 
+    std::string slot_suffix = SlotSuffixForSlotNumber(slot_number);
+
     // Before writing geometry and/or logical partition tables, perform some
     // basic checks that the geometry and tables are coherent, and will fit
     // on the given block device.
     std::string blob;
-    if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
+    if (!ValidateAndSerializeMetadata(opener, metadata, slot_suffix, &blob)) {
         return false;
     }
 
@@ -335,7 +351,7 @@
         // synchronize the backup copy. This guarantees that a partial write
         // still leaves one copy intact.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *primary.get(), slot_suffix, &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }
@@ -347,7 +363,7 @@
         // The backup copy is coherent, and the primary is not. Sync it for
         // safety.
         std::string old_blob;
-        if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
+        if (!ValidateAndSerializeMetadata(opener, *backup.get(), slot_suffix, &old_blob)) {
             LERROR << "Error serializing primary metadata to repair corrupted backup";
             return false;
         }
diff --git a/init/README.md b/init/README.md
index 2c531df..5c07ac1 100644
--- a/init/README.md
+++ b/init/README.md
@@ -275,6 +275,10 @@
   since it has some peculiarities for backwards compatibility reasons. The 'imports' section of
   this file has more details on the order.
 
+`parse_apex_configs`
+  Parses config file(s) from the mounted APEXes. Intented to be used only once
+  when apexd notifies the mount event by setting apexd.status to ready.
+
 `priority <priority>`
 > Scheduling priority of the service process. This value has to be in range
   -20 to 19. Default priority is 0. Priority is set via setpriority().
@@ -328,6 +332,13 @@
   This is particularly useful for creating a periodic service combined with the restart_period
   option described above.
 
+`updatable`
+> Mark that the service can be overridden (via the 'override' option) later in
+  the boot sequence by APEXes. When a service with updatable option is started
+  before APEXes are all activated, the execution is delayed until the activation
+  is finished. A service that is not marked as updatable cannot be overridden by
+  APEXes.
+
 `user <username>`
 > Change to 'username' before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 5d62c0b..5676f92 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
+#include <glob.h>
 #include <linux/loop.h>
 #include <linux/module.h>
 #include <mntent.h>
@@ -1053,6 +1054,39 @@
         {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
 }
 
+static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
+    glob_t glob_result;
+    // @ is added to filter out the later paths, which are bind mounts of the places
+    // where the APEXes are really mounted at. Otherwise, we will parse the
+    // same file twice.
+    static constexpr char glob_pattern[] = "/apex/*@*/etc/*.rc";
+    if (glob(glob_pattern, GLOB_MARK, nullptr, &glob_result) != 0) {
+        globfree(&glob_result);
+        return Error() << "glob pattern '" << glob_pattern << "' failed";
+    }
+    std::vector<std::string> configs;
+    Parser parser = CreateServiceOnlyParser(ServiceList::GetInstance());
+    for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+        configs.emplace_back(glob_result.gl_pathv[i]);
+    }
+    globfree(&glob_result);
+
+    bool success = true;
+    for (const auto& c : configs) {
+        if (c.back() == '/') {
+            // skip if directory
+            continue;
+        }
+        success &= parser.ParseConfigFile(c);
+    }
+    ServiceList::GetInstance().MarkServicesUpdate();
+    if (success) {
+        return Success();
+    } else {
+        return Error() << "Could not parse apex configs";
+    }
+}
+
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1090,6 +1124,7 @@
         // mount and umount are run in the same context as mount_all for symmetry.
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
+        {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index d658f4d..3e7c1a8 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -16,8 +16,8 @@
 
 #include "devices.h"
 
+#include <android-base/file.h>
 #include <android-base/scopeguard.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include "util.h"
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 13a9d08..1e434d2 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -17,6 +17,7 @@
 #include "first_stage_mount.h"
 
 #include <stdlib.h>
+#include <sys/mount.h>
 #include <unistd.h>
 
 #include <chrono>
@@ -123,18 +124,8 @@
     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
 }
 
-static bool ForceNormalBoot() {
-    static bool force_normal_boot = []() {
-        std::string cmdline;
-        android::base::ReadFileToString("/proc/cmdline", &cmdline);
-        return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
-    }();
-
-    return force_normal_boot;
-}
-
 static bool IsRecoveryMode() {
-    return !ForceNormalBoot() && access("/system/bin/recovery", F_OK) == 0;
+    return access("/system/bin/recovery", F_OK) == 0;
 }
 
 // Class Definitions
@@ -403,11 +394,6 @@
                          [](const auto& rec) { return rec->mount_point == "/system"s; });
 
     if (system_partition != mount_fstab_recs_.end()) {
-        if (ForceNormalBoot()) {
-            free((*system_partition)->mount_point);
-            (*system_partition)->mount_point = strdup("/system_recovery_mount");
-        }
-
         if (!MountPartition(*system_partition)) {
             return false;
         }
@@ -574,7 +560,7 @@
         std::vector<std::string> links = device_handler_->GetBlockDeviceSymlinks(uevent);
         if (!links.empty()) {
             auto [it, inserted] = by_name_symlink_map_.emplace(uevent.partition_name, links[0]);
-            if (!inserted) {
+            if (!inserted && (links[0] != it->second)) {
                 LOG(ERROR) << "Partition '" << uevent.partition_name
                            << "' already existed in the by-name symlink map with a value of '"
                            << it->second << "', new value '" << links[0] << "' will be ignored.";
diff --git a/init/init.cpp b/init/init.cpp
index 90803f7..e7dbc11 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -132,6 +132,14 @@
     return parser;
 }
 
+// parser that only accepts new services
+Parser CreateServiceOnlyParser(ServiceList& service_list) {
+    Parser parser;
+
+    parser.AddSectionParser("service", std::make_unique<ServiceParser>(&service_list, subcontexts));
+    return parser;
+}
+
 static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
     Parser parser = CreateParser(action_manager, service_list);
 
diff --git a/init/init.h b/init/init.h
index f244ad7..65405aa 100644
--- a/init/init.h
+++ b/init/init.h
@@ -38,6 +38,7 @@
 extern std::vector<std::string> late_import_paths;
 
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
+Parser CreateServiceOnlyParser(ServiceList& service_list);
 
 void HandleControlMessage(const std::string& msg, const std::string& arg, pid_t pid);
 
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index d81ca5c..c2c6868 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <dirent.h>
+#include <fcntl.h>
 #include <paths.h>
 #include <stdlib.h>
 #include <sys/mount.h>
@@ -26,19 +28,72 @@
 #include <vector>
 
 #include <android-base/chrono_utils.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <cutils/android_reboot.h>
 #include <private/android_filesystem_config.h>
 
 #include "first_stage_mount.h"
 #include "reboot_utils.h"
+#include "switch_root.h"
 #include "util.h"
 
 using android::base::boot_clock;
 
+using namespace std::literals;
+
 namespace android {
 namespace init {
 
+namespace {
+
+void FreeRamdisk(DIR* dir, dev_t dev) {
+    int dfd = dirfd(dir);
+
+    dirent* de;
+    while ((de = readdir(dir)) != nullptr) {
+        if (de->d_name == "."s || de->d_name == ".."s) {
+            continue;
+        }
+
+        bool is_dir = false;
+
+        if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
+            struct stat info;
+            if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
+                continue;
+            }
+
+            if (info.st_dev != dev) {
+                continue;
+            }
+
+            if (S_ISDIR(info.st_mode)) {
+                is_dir = true;
+                auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+                if (fd >= 0) {
+                    auto subdir =
+                            std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
+                    if (subdir) {
+                        FreeRamdisk(subdir.get(), dev);
+                    } else {
+                        close(fd);
+                    }
+                }
+            }
+        }
+        unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
+    }
+}
+
+bool ForceNormalBoot() {
+    std::string cmdline;
+    android::base::ReadFileToString("/proc/cmdline", &cmdline);
+    return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
+}
+
+}  // namespace
+
 int main(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -117,10 +172,41 @@
 
     LOG(INFO) << "init first stage started!";
 
+    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
+    if (!old_root_dir) {
+        PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
+    }
+
+    struct stat old_root_info;
+    if (stat("/", &old_root_info) != 0) {
+        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+        old_root_dir.reset();
+    }
+
+    if (ForceNormalBoot()) {
+        mkdir("/first_stage_ramdisk", 0755);
+        // SwitchRoot() must be called with a mount point as the target, so we bind mount the
+        // target directory to itself here.
+        if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
+            LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
+        }
+        SwitchRoot("/first_stage_ramdisk");
+    }
+
     if (!DoFirstStageMount()) {
         LOG(FATAL) << "Failed to mount required partitions early ...";
     }
 
+    struct stat new_root_info;
+    if (stat("/", &new_root_info) != 0) {
+        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
+        old_root_dir.reset();
+    }
+
+    if (old_root_dir && old_root_info.st_dev != new_root_info.st_dev) {
+        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
+    }
+
     SetInitAvbVersionInRecovery();
 
     static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0f9635f..c2f0c41 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -17,7 +17,6 @@
 #include <functional>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include "action.h"
diff --git a/init/parser.h b/init/parser.h
index 2454b6a..f30bda7 100644
--- a/init/parser.h
+++ b/init/parser.h
@@ -72,6 +72,7 @@
     Parser();
 
     bool ParseConfig(const std::string& path);
+    bool ParseConfigFile(const std::string& path);
     void AddSectionParser(const std::string& name, std::unique_ptr<SectionParser> parser);
     void AddSingleLineParser(const std::string& prefix, LineCallback callback);
 
@@ -82,7 +83,6 @@
 
   private:
     void ParseData(const std::string& filename, std::string* data);
-    bool ParseConfigFile(const std::string& path);
     bool ParseConfigDir(const std::string& path);
 
     std::map<std::string, std::unique_ptr<SectionParser>> section_parsers_;
diff --git a/init/persistent_properties_test.cpp b/init/persistent_properties_test.cpp
index 872e9a1..13796a6 100644
--- a/init/persistent_properties_test.cpp
+++ b/init/persistent_properties_test.cpp
@@ -20,7 +20,7 @@
 
 #include <vector>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 
 #include "util.h"
diff --git a/init/service.cpp b/init/service.cpp
index 1bda7ec..5aa3764 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -765,6 +765,11 @@
     return Success();
 }
 
+Result<Success> Service::ParseUpdatable(std::vector<std::string>&& args) {
+    updatable_ = true;
+    return Success();
+}
+
 class Service::OptionParserMap : public KeywordMap<OptionParser> {
   public:
     OptionParserMap() {}
@@ -817,6 +822,7 @@
         {"socket",      {3,     6,    &Service::ParseSocket}},
         {"timeout_period",
                         {1,     1,    &Service::ParseTimeoutPeriod}},
+        {"updatable",   {0,     0,    &Service::ParseUpdatable}},
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
@@ -834,6 +840,13 @@
 }
 
 Result<Success> Service::ExecStart() {
+    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+        // Don't delay the service for ExecStart() as the semantic is that
+        // the caller might depend on the side effect of the execution.
+        return Error() << "Cannot start an updatable service '" << name_
+                       << "' before configs from APEXes are all loaded";
+    }
+
     flags_ |= SVC_ONESHOT;
 
     if (auto result = Start(); !result) {
@@ -851,6 +864,13 @@
 }
 
 Result<Success> Service::Start() {
+    if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) {
+        ServiceList::GetInstance().DelayService(*this);
+        return Error() << "Cannot start an updatable service '" << name_
+                       << "' before configs from APEXes are all loaded. "
+                       << "Queued for execution.";
+    }
+
     bool disabled = (flags_ & (SVC_DISABLED | SVC_RESET));
     // Starting a service removes it from the disabled or reset state and
     // immediately takes it out of the restarting state if it was in there.
@@ -1280,6 +1300,32 @@
     }
 }
 
+void ServiceList::MarkServicesUpdate() {
+    services_update_finished_ = true;
+
+    // start the delayed services
+    for (const auto& name : delayed_service_names_) {
+        Service* service = FindService(name);
+        if (service == nullptr) {
+            LOG(ERROR) << "delayed service '" << name << "' could not be found.";
+            continue;
+        }
+        if (auto result = service->Start(); !result) {
+            LOG(ERROR) << result.error_string();
+        }
+    }
+    delayed_service_names_.clear();
+}
+
+void ServiceList::DelayService(const Service& service) {
+    if (services_update_finished_) {
+        LOG(ERROR) << "Cannot delay the start of service '" << service.name()
+                   << "' because all services are already updated. Ignoring.";
+        return;
+    }
+    delayed_service_names_.emplace_back(service.name());
+}
+
 Result<Success> ServiceParser::ParseSection(std::vector<std::string>&& args,
                                             const std::string& filename, int line) {
     if (args.size() < 3) {
@@ -1291,6 +1337,8 @@
         return Error() << "invalid service name '" << name << "'";
     }
 
+    filename_ = filename;
+
     Subcontext* restart_action_subcontext = nullptr;
     if (subcontexts_) {
         for (auto& subcontext : *subcontexts_) {
@@ -1326,6 +1374,11 @@
                                << "'";
             }
 
+            if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) {
+                return Error() << "cannot update a non-updatable service '" << service_->name()
+                               << "' with a config in APEX";
+            }
+
             service_list_->RemoveService(*old_service);
             old_service = nullptr;
         }
diff --git a/init/service.h b/init/service.h
index 49b09ce..56e75b0 100644
--- a/init/service.h
+++ b/init/service.h
@@ -123,6 +123,7 @@
     std::chrono::seconds restart_period() const { return restart_period_; }
     std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
     const std::vector<std::string>& args() const { return args_; }
+    bool is_updatable() const { return updatable_; }
 
   private:
     using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -170,6 +171,7 @@
     Result<Success> ParseFile(std::vector<std::string>&& args);
     Result<Success> ParseUser(std::vector<std::string>&& args);
     Result<Success> ParseWritepid(std::vector<std::string>&& args);
+    Result<Success> ParseUpdatable(std::vector<std::string>&& args);
 
     template <typename T>
     Result<Success> AddDescriptor(std::vector<std::string>&& args);
@@ -235,6 +237,8 @@
     std::chrono::seconds restart_period_ = 5s;
     std::optional<std::chrono::seconds> timeout_period_;
 
+    bool updatable_ = false;
+
     std::vector<std::string> args_;
 
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
@@ -279,8 +283,15 @@
     const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
     const std::vector<Service*> services_in_shutdown_order() const;
 
+    void MarkServicesUpdate();
+    bool IsServicesUpdated() const { return services_update_finished_; }
+    void DelayService(const Service& service);
+
   private:
     std::vector<std::unique_ptr<Service>> services_;
+
+    bool services_update_finished_ = false;
+    std::vector<std::string> delayed_service_names_;
 };
 
 class ServiceParser : public SectionParser {
@@ -291,6 +302,7 @@
                                  int line) override;
     Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
     Result<Success> EndSection() override;
+    void EndFile() override { filename_ = ""; }
 
   private:
     bool IsValidName(const std::string& name) const;
@@ -298,6 +310,7 @@
     ServiceList* service_list_;
     std::vector<Subcontext>* subcontexts_;
     std::unique_ptr<Service> service_;
+    std::string filename_;
 };
 
 }  // namespace init
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index 0e59b57..575b67f 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -16,7 +16,6 @@
 
 #include "switch_root.h"
 
-#include <dirent.h>
 #include <fcntl.h>
 #include <mntent.h>
 #include <sys/mount.h>
@@ -35,45 +34,6 @@
 
 namespace {
 
-void FreeRamdisk(DIR* dir, dev_t dev) {
-    int dfd = dirfd(dir);
-
-    dirent* de;
-    while ((de = readdir(dir)) != nullptr) {
-        if (de->d_name == "."s || de->d_name == ".."s) {
-            continue;
-        }
-
-        bool is_dir = false;
-
-        if (de->d_type == DT_DIR || de->d_type == DT_UNKNOWN) {
-            struct stat info;
-            if (fstatat(dfd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) != 0) {
-                continue;
-            }
-
-            if (info.st_dev != dev) {
-                continue;
-            }
-
-            if (S_ISDIR(info.st_mode)) {
-                is_dir = true;
-                auto fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
-                if (fd >= 0) {
-                    auto subdir =
-                            std::unique_ptr<DIR, decltype(&closedir)>{fdopendir(fd), closedir};
-                    if (subdir) {
-                        FreeRamdisk(subdir.get(), dev);
-                    } else {
-                        close(fd);
-                    }
-                }
-            }
-        }
-        unlinkat(dfd, de->d_name, is_dir ? AT_REMOVEDIR : 0);
-    }
-}
-
 std::vector<std::string> GetMounts(const std::string& new_root) {
     auto fp = std::unique_ptr<std::FILE, decltype(&endmntent)>{setmntent("/proc/mounts", "re"),
                                                                endmntent};
@@ -112,24 +72,16 @@
 void SwitchRoot(const std::string& new_root) {
     auto mounts = GetMounts(new_root);
 
+    LOG(INFO) << "Switching root to '" << new_root << "'";
+
     for (const auto& mount_path : mounts) {
         auto new_mount_path = new_root + mount_path;
+        mkdir(new_mount_path.c_str(), 0755);
         if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
             PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
         }
     }
 
-    auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
-    if (!old_root_dir) {
-        PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
-    }
-
-    struct stat old_root_info;
-    if (stat("/", &old_root_info) != 0) {
-        PLOG(ERROR) << "Could not stat(\"/\"), not freeing ramdisk";
-        old_root_dir.reset();
-    }
-
     if (chdir(new_root.c_str()) != 0) {
         PLOG(FATAL) << "Could not chdir to new_root, '" << new_root << "'";
     }
@@ -141,10 +93,6 @@
     if (chroot(".") != 0) {
         PLOG(FATAL) << "Unable to chroot to new root";
     }
-
-    if (old_root_dir) {
-        FreeRamdisk(old_root_dir.get(), old_root_info.st_dev);
-    }
 }
 
 }  // namespace init
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index 31208b9..c3af341 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -16,7 +16,7 @@
 
 #include "ueventd_parser.h"
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 #include <gtest/gtest.h>
 #include <private/android_filesystem_config.h>
 
diff --git a/init/ueventd_test.cpp b/init/ueventd_test.cpp
index 7290051..bfdc28e 100644
--- a/init/ueventd_test.cpp
+++ b/init/ueventd_test.cpp
@@ -27,7 +27,6 @@
 
 #include <android-base/file.h>
 #include <android-base/scopeguard.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 #include <selinux/android.h>
 #include <selinux/label.h>
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 3ae53a4..1b5afba 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -20,8 +20,8 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 using namespace std::literals::string_literals;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index bd5f26f..ee52f5e 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -60,7 +60,7 @@
 // way up to the root.
 
 static const struct fs_path_config android_dirs[] = {
-    // clang-format off
+        // clang-format off
     { 00770, AID_SYSTEM,       AID_CACHE,        0, "cache" },
     { 00555, AID_ROOT,         AID_ROOT,         0, "config" },
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data/app" },
@@ -80,17 +80,18 @@
     { 00775, AID_ROOT,         AID_ROOT,         0, "data/preloads" },
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data" },
     { 00755, AID_ROOT,         AID_SYSTEM,       0, "mnt" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "product/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "product/bin" },
     { 00750, AID_ROOT,         AID_SHELL,        0, "sbin" },
     { 00777, AID_ROOT,         AID_ROOT,         0, "sdcard" },
     { 00751, AID_ROOT,         AID_SDCARD_R,     0, "storage" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "system/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system/bin" },
     { 00755, AID_ROOT,         AID_ROOT,         0, "system/etc/ppp" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
-    { 00755, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
-    // clang-format on
+        // clang-format on
 };
 #ifndef __ANDROID_VNDK__
 auto __for_testing_only__android_dirs = android_dirs;
diff --git a/libcutils/tests/android_get_control_file_test.cpp b/libcutils/tests/android_get_control_file_test.cpp
index 6c6fd2a..8de8530 100644
--- a/libcutils/tests/android_get_control_file_test.cpp
+++ b/libcutils/tests/android_get_control_file_test.cpp
@@ -23,8 +23,8 @@
 
 #include <string>
 
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
 #include <cutils/android_get_control_file.h>
 #include <gtest/gtest.h>
 
diff --git a/libcutils/tests/trace-dev_test.cpp b/libcutils/tests/trace-dev_test.cpp
index f8d4f00..832b36a 100644
--- a/libcutils/tests/trace-dev_test.cpp
+++ b/libcutils/tests/trace-dev_test.cpp
@@ -22,7 +22,6 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include "../trace-dev.cpp"
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 3820776b..e2239f0 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -24,7 +24,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/test_utils.h>
 
 #include <benchmark/benchmark.h>
 
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 22f3585..7a2be41 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -30,7 +30,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/test_utils.h>
 
 using namespace std;
 using namespace android::meminfo;
diff --git a/libmemunreachable/Android.bp b/libmemunreachable/Android.bp
index 248a9d2..b78a4c4 100644
--- a/libmemunreachable/Android.bp
+++ b/libmemunreachable/Android.bp
@@ -46,12 +46,6 @@
             static_libs: ["libunwind_llvm"],
         },
     },
-
-    // TODO(b/78118944), clang lld link flags do not work with special link
-    // rules for libunwind_llvm yet. Linked aosp_arm-eng image failed to
-    // boot up in the emulator.
-    use_clang_lld: false,
-
     export_include_dirs: ["include"],
     local_include_dirs: ["include"],
 }
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 40f9f8e..95d2176 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -20,7 +20,7 @@
 
 #include <unordered_map>
 
-#include <android-base/test_utils.h>
+#include <android-base/file.h>
 
 #include <unwindstack/MapInfo.h>
 #include <unwindstack/Memory.h>
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index d9acdec..07fd6f6 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -18,7 +18,6 @@
 #include <unistd.h>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 
 #include <gtest/gtest.h>
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2a73c7e..0987bc1 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -27,7 +27,6 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 4d74696..f3b4679 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -29,7 +29,6 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
index 6bdd0b2..80e292a 100644
--- a/libunwindstack/tests/MapsTest.cpp
+++ b/libunwindstack/tests/MapsTest.cpp
@@ -19,7 +19,6 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/Maps.h>
diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp
index 14d58e6..ab9aa9d 100644
--- a/libunwindstack/tests/MemoryOfflineTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineTest.cpp
@@ -19,7 +19,6 @@
 #include <gtest/gtest.h>
 
 #include <android-base/file.h>
-#include <android-base/test_utils.h>
 #include <unwindstack/Memory.h>
 
 namespace unwindstack {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 0ea7d5d..500a531 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -28,7 +28,6 @@
 
 #include <android-base/file.h>
 #include <android-base/mapped_file.h>
-#include <android-base/test_utils.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 #include <ziparchive/zip_archive.h>
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1715501..208d67f 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -204,6 +204,10 @@
         goto skip;
     }
 
+    if (me->mRelease) {
+        goto stop;
+    }
+
     if (!me->mTail) {
         goto ok;
     }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 025e3c3..636daea 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -801,3 +801,6 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
+
+on property:apexd.status=ready
+    parse_apex_configs
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
index 971b9f4..f49bdf7 100644
--- a/run-as/run-as.cpp
+++ b/run-as/run-as.cpp
@@ -25,6 +25,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <string>
+
 #include <libminijail.h>
 #include <scoped_minijail.h>
 
@@ -214,7 +216,8 @@
   minijail_keep_supplementary_gids(j.get());
   minijail_enter(j.get());
 
-  if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
+  std::string seinfo = std::string(info.seinfo) + ":fromRunAs";
+  if (selinux_android_setcontext(uid, 0, seinfo.c_str(), pkgname) < 0) {
     error(1, errno, "couldn't set SELinux security context");
   }