Merge "Do SetUpDmVerity only once for the same mount point"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 21e0874..d56a25f 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -35,7 +35,6 @@
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
-#include "sysdeps.h"
 
 static constexpr int kFastDeployMinApi = 24;
 
@@ -161,17 +160,23 @@
 
     if (use_fastdeploy == true) {
         TemporaryFile metadataTmpFile;
-        TemporaryFile patchTmpFile;
+        std::string patchTmpFilePath;
+        {
+            TemporaryFile patchTmpFile;
+            patchTmpFile.DoNotRemove();
+            patchTmpFilePath = patchTmpFile.path;
+        }
 
         FILE* metadataFile = fopen(metadataTmpFile.path, "wb");
         extract_metadata(file, metadataFile);
         fclose(metadataFile);
 
-        create_patch(file, metadataTmpFile.path, patchTmpFile.path);
+        create_patch(file, metadataTmpFile.path, patchTmpFilePath.c_str());
         // pass all but 1st (command) and last (apk path) parameters through to pm for
         // session creation
         std::vector<const char*> pm_args{argv + 1, argv + argc - 1};
-        install_patch(file, patchTmpFile.path, pm_args.size(), pm_args.data());
+        install_patch(file, patchTmpFilePath.c_str(), pm_args.size(), pm_args.data());
+        adb_unlink(patchTmpFilePath.c_str());
         delete_device_patch_file(file);
         return 0;
     } else {
diff --git a/adb/client/line_printer.cpp b/adb/client/line_printer.cpp
index 4dc2d28..50c03e8 100644
--- a/adb/client/line_printer.cpp
+++ b/adb/client/line_printer.cpp
@@ -31,6 +31,8 @@
 // Stuff from ninja's util.h that's needed below.
 #include <vector>
 using namespace std;
+// This does not account for multiple UTF-8 bytes corresponding to a single Unicode code point, or
+// multiple code points corresponding to a single grapheme cluster (user-perceived character).
 string ElideMiddle(const string& str, size_t width) {
   const int kMargin = 3;  // Space for "...".
   string result = str;
@@ -85,9 +87,10 @@
     CONSOLE_SCREEN_BUFFER_INFO csbi;
     GetConsoleScreenBufferInfo(console_, &csbi);
 
-    // TODO: std::wstring to_print_wide; if (!android::base::UTF8ToWide(to_print, &to_print_wide)...
-    // TODO: wstring ElideMiddle.
     to_print = ElideMiddle(to_print, static_cast<size_t>(csbi.dwSize.X));
+    std::wstring to_print_wide;
+    // ElideMiddle may create invalid UTF-8, so ignore conversion errors.
+    (void)android::base::UTF8ToWide(to_print, &to_print_wide);
     // We don't want to have the cursor spamming back and forth, so instead of
     // printf use WriteConsoleOutput which updates the contents of the buffer,
     // but doesn't move the cursor position.
@@ -100,12 +103,10 @@
     };
     vector<CHAR_INFO> char_data(csbi.dwSize.X);
     for (size_t i = 0; i < static_cast<size_t>(csbi.dwSize.X); ++i) {
-      // TODO: UnicodeChar instead of AsciiChar, to_print_wide[i].
-      char_data[i].Char.AsciiChar = i < to_print.size() ? to_print[i] : ' ';
-      char_data[i].Attributes = csbi.wAttributes;
+        char_data[i].Char.UnicodeChar = i < to_print_wide.size() ? to_print_wide[i] : L' ';
+        char_data[i].Attributes = csbi.wAttributes;
     }
-    // TODO: WriteConsoleOutputW.
-    WriteConsoleOutput(console_, &char_data[0], buf_size, zero_zero, &target);
+    WriteConsoleOutputW(console_, &char_data[0], buf_size, zero_zero, &target);
 #else
     // Limit output to width of the terminal if provided so we don't cause
     // line-wrapping.
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index dbc8920..d587589 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -719,7 +719,7 @@
 /**************************************************************************/
 /**************************************************************************/
 
-static int _init_winsock(void) {
+static void _init_winsock() {
     static std::once_flag once;
     std::call_once(once, []() {
         WSADATA wsaData;
@@ -743,11 +743,8 @@
         //    crypt32.dll which calls atexit() which tries to acquire the C
         //    Runtime lock that the other thread holds.
     });
-    return 0;
 }
 
-static int _winsock_init = _init_winsock();
-
 // Map a socket type to an explicit socket protocol instead of using the socket
 // protocol of 0. Explicit socket protocols are used by most apps and we should
 // do the same to reduce the chance of exercising uncommon code-paths that might
@@ -2621,14 +2618,13 @@
 }
 
 // Shadow UTF-8 environment variable name/value pairs that are created from
-// _wenviron the first time that adb_getenv() is called. Note that this is not
-// currently updated if putenv, setenv, unsetenv are called. Note that no
-// thread synchronization is done, but we're called early enough in
+// _wenviron by _init_env(). Note that this is not currently updated if putenv, setenv, unsetenv are
+// called. Note that no thread synchronization is done, but we're called early enough in
 // single-threaded startup that things work ok.
 static auto& g_environ_utf8 = *new std::unordered_map<std::string, char*>();
 
-// Make sure that shadow UTF-8 environment variables are setup.
-static void _ensure_env_setup() {
+// Setup shadow UTF-8 environment variables.
+static void _init_env() {
     // If some name/value pairs exist, then we've already done the setup below.
     if (g_environ_utf8.size() != 0) {
         return;
@@ -2681,8 +2677,6 @@
 // Version of getenv() that takes a UTF-8 environment variable name and
 // retrieves a UTF-8 value. Case-insensitive to match getenv() on Windows.
 char* adb_getenv(const char* name) {
-    _ensure_env_setup();
-
     // Case-insensitive search by searching for lowercase name in a map of
     // lowercase names.
     const auto it = g_environ_utf8.find(ToLower(std::string(name)));
@@ -2757,3 +2751,65 @@
 
     return 0;
 }
+
+#if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+#if !defined(DISABLE_NEWLINE_AUTO_RETURN)
+#define DISABLE_NEWLINE_AUTO_RETURN 0x0008
+#endif
+
+static void _init_console() {
+    DWORD old_out_console_mode;
+
+    const HANDLE out = _get_console_handle(STDOUT_FILENO, &old_out_console_mode);
+    if (out == nullptr) {
+        return;
+    }
+
+    // Try to use ENABLE_VIRTUAL_TERMINAL_PROCESSING on the output console to process virtual
+    // terminal sequences on newer versions of Windows 10 and later.
+    // https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
+    // On older OSes that don't support the flag, SetConsoleMode() will return an error.
+    // ENABLE_VIRTUAL_TERMINAL_PROCESSING also solves a problem where the last column of the
+    // console cannot be overwritten.
+    //
+    // Note that we don't use DISABLE_NEWLINE_AUTO_RETURN because it doesn't seem to be necessary.
+    // If we use DISABLE_NEWLINE_AUTO_RETURN, _console_write_utf8() would need to be modified to
+    // translate \n to \r\n.
+    if (!SetConsoleMode(out, old_out_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+        return;
+    }
+
+    // If SetConsoleMode() succeeded, the console supports virtual terminal processing, so we
+    // should set the TERM env var to match so that it will be propagated to adbd on devices.
+    //
+    // Below's direct manipulation of env vars and not g_environ_utf8 assumes that _init_env() has
+    // not yet been called. If this fails, _init_env() should be called after _init_console().
+    if (g_environ_utf8.size() > 0) {
+        LOG(FATAL) << "environment variables have already been converted to UTF-8";
+    }
+
+#pragma push_macro("getenv")
+#undef getenv
+#pragma push_macro("putenv")
+#undef putenv
+    if (getenv("TERM") == nullptr) {
+        // This is the same TERM value used by Gnome Terminal and the version of ssh included with
+        // Windows.
+        putenv("TERM=xterm-256color");
+    }
+#pragma pop_macro("putenv")
+#pragma pop_macro("getenv")
+}
+
+static bool _init_sysdeps() {
+    // _init_console() depends on _init_env() not being called yet.
+    _init_console();
+    _init_env();
+    _init_winsock();
+    return true;
+}
+
+static bool _sysdeps_init = _init_sysdeps();
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 3908683..2c4299a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -626,8 +626,8 @@
 
 // Only a suggestion for _first_ try during mounting
 std::string fs_mgr_overlayfs_scratch_mount_type() {
-    if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
-    if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
+    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_access("/sys/fs/f2fs")) return "f2fs";
+    if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_access("/sys/fs/ext4")) return "ext4";
     return "auto";
 }
 
@@ -642,7 +642,11 @@
         // Create from within single super device;
         auto& dm = DeviceMapper::Instance();
         const auto partition_name = android::base::Basename(kScratchMountPoint);
-        if (!dm.GetDmDevicePathByName(partition_name, &path)) return "";
+        if (!dm.GetDmDevicePathByName(partition_name, &path)) {
+            // non-DAP A/B device?
+            if (fs_mgr_access(super_device)) return "";
+            path = kPhysicalDevice + "system" + (slot_number ? "_a" : "_b");
+        }
     }
     return scratch_device_cache = path;
 }
@@ -829,8 +833,9 @@
                                                    true /* readonly */)) {
                     auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
                     fs_mgr_overlayfs_umount_scratch();
-                    if (has_overlayfs_dir)
+                    if (has_overlayfs_dir) {
                         fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+                    }
                 }
             }
         }
@@ -882,10 +887,6 @@
     for (const auto& overlay_mount_point : kOverlayMountPoints) {
         if (backing && backing[0] && (overlay_mount_point != backing)) continue;
         if (overlay_mount_point == kScratchMountPoint) {
-            if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
-                !fs_mgr_overlayfs_has_logical(fstab)) {
-                continue;
-            }
             if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
         } else {
             if (std::find_if(fstab.begin(), fstab.end(), [&overlay_mount_point](const auto& entry) {
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 164fc91..6ccdb57 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -359,6 +359,21 @@
     return moved_blocks_nr == 0;
 }
 
+bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
+    android::base::unique_fd fd(open(file_path.c_str(), O_NOFOLLOW | O_CLOEXEC | O_RDONLY));
+    if (fd < 0) {
+        PLOG(ERROR) << "open: " << file_path;
+        return false;
+    }
+
+    struct statfs64 sfs;
+    if (fstatfs64(fd, &sfs)) {
+        PLOG(ERROR) << "fstatfs64: " << file_path;
+        return false;
+    }
+    return IsFilePinned(fd, file_path, sfs.f_type);
+}
+
 static void LogExtent(uint32_t num, const struct fiemap_extent& ext) {
     LOG(INFO) << "Extent #" << num;
     LOG(INFO) << "  fe_logical:  " << ext.fe_logical;
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 5101537..3d20ff3 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -51,6 +51,8 @@
         testfile = ::android::base::StringPrintf("%s/testdata/%s", exec_dir.c_str(), tinfo->name());
     }
 
+    void TearDown() override { unlink(testfile.c_str()); }
+
     // name of the file we use for testing
     std::string testfile;
 };
@@ -102,6 +104,12 @@
     EXPECT_EQ(invocations, 2);
 }
 
+TEST_F(FiemapWriterTest, CheckPinning) {
+    auto ptr = FiemapWriter::Open(testfile, 4096);
+    ASSERT_NE(ptr, nullptr);
+    EXPECT_TRUE(FiemapWriter::HasPinnedExtents(testfile));
+}
+
 TEST_F(FiemapWriterTest, CheckBlockDevicePath) {
     FiemapUniquePtr fptr = FiemapWriter::Open(testfile, 4096);
     EXPECT_EQ(fptr->size(), 4096);
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
index ab78f93..a0085cf 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
@@ -45,6 +45,18 @@
                                 bool create = true,
                                 std::function<bool(uint64_t, uint64_t)> progress = {});
 
+    // Check that a file still has the same extents since it was last opened with FiemapWriter,
+    // assuming the file was not resized outside of FiemapWriter. Returns false either on error
+    // or if the file was not pinned.
+    //
+    // This will always return true on Ext4. On F2FS, it will return true if either of the
+    // following cases are true:
+    //   - The file was never pinned.
+    //   - The file is pinned and has not been moved by the GC.
+    // Thus, this method should only be called for pinned files (such as those returned by
+    // FiemapWriter::Open).
+    static bool HasPinnedExtents(const std::string& file_path);
+
     // Syncs block device writes.
     bool Flush() const;
 
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 0765f04..42f3f29 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -309,7 +309,7 @@
     -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
     -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
     -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
-    -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\) "
+    -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
 }
 
 if [ X"-s" = X"${1}" -a -n "${2}" ]; then
@@ -403,9 +403,15 @@
      echo "${D}" | grep -v /dev/root`
 fi
 D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
+no_dedupe=true
+for d in ${D}; do
+  adb_sh tune2fs -l $d 2>&1 |
+    grep "Filesystem features:.*shared_blocks" >/dev/null &&
+  no_dedupe=false
+done
 D=`adb_sh df -k ${D} </dev/null`
 echo "${D}"
-if [ X"${D}" = X"${D##* 100[%] }" ]; then
+if [ X"${D}" = X"${D##* 100[%] }" ] && ${no_dedupe} ; then
   overlayfs_needed=false
 elif ! ${overlayfs_supported}; then
   die "need overlayfs, but do not have it"
@@ -597,6 +603,7 @@
 echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
 
 H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+is_userspace_fastboot=false
 if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
 elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
@@ -609,6 +616,8 @@
     fastboot flash vendor ||
     ( fastboot reboot && false) ||
     die "fastboot flash vendor"
+  fastboot_getvar is-userspace yes &&
+    is_userspace_fastboot=true
   if [ -n "${scratch_paritition}" ]; then
     fastboot_getvar partition-type:${scratch_partition} raw ||
       ( fastboot reboot && false) ||
@@ -654,7 +663,12 @@
       echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
       die  "overlay /system takeover after flash vendor"
     echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
-      die  "overlay supposed to be minus /vendor takeover after flash vendor"
+      if ${is_userspace_fastboot}; then
+        die  "overlay supposed to be minus /vendor takeover after flash vendor"
+      else
+        echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+        ( die  "overlay supposed to be minus /vendor takeover after flash vendor" )
+      fi
   fi
   B="`adb_cat /system/hello`" ||
     die "re-read /system/hello after flash vendor"
@@ -662,8 +676,17 @@
   adb_root ||
     die "adb root"
   B="`adb_cat /vendor/hello`" &&
-    die "re-read /vendor/hello after flash vendor"
-  check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+    if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+      die "re-read /vendor/hello after flash vendor"
+    else
+      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing, ignoring a failure"
+      ( die "re-read /vendor/hello after flash vendor" )
+    fi
+  if ${is_userspace_fastboot} || ! ${overlayfs_needed}; then
+    check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
+  else
+    ( check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor )
+  fi
 fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} remove test content (cleanup)" >&2
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 2127b96..80bf84a 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -109,7 +109,6 @@
     libbase \
     libutils \
     libcutils \
-    libprocessgroup \
     liblog \
     libm \
     libc \
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0dbbc3f..4291212 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -66,6 +66,7 @@
         "load_file.cpp",
         "native_handle.cpp",
         "record_stream.cpp",
+        "sched_policy.cpp",
         "sockets.cpp",
         "strdup16to8.cpp",
         "strdup8to16.cpp",
@@ -177,12 +178,8 @@
         "libbase_headers",
         "libcutils_headers",
         "libutils_headers",
-        "libprocessgroup_headers",
     ],
-    export_header_lib_headers: [
-        "libcutils_headers",
-        "libprocessgroup_headers",
-    ],
+    export_header_lib_headers: ["libcutils_headers"],
     local_include_dirs: ["include"],
 
     cflags: [
diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h
index 538ff6b..cf91b76 100644
--- a/libcutils/include/cutils/sched_policy.h
+++ b/libcutils/include/cutils/sched_policy.h
@@ -17,10 +17,67 @@
 #ifndef __CUTILS_SCHED_POLICY_H
 #define __CUTILS_SCHED_POLICY_H
 
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*
- * For backwards compatibility only
- * New users should include processgroup/sched_policy.h directly
+ * Check if Linux kernel enables CPUSETS feature.
+ *
+ * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
  */
-#include <processgroup/sched_policy.h>
+extern bool cpusets_enabled();
+
+/*
+ * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
+ * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
+ *
+ * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
+ */
+extern bool schedboost_enabled();
+
+/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
+typedef enum {
+    SP_DEFAULT = -1,
+    SP_BACKGROUND = 0,
+    SP_FOREGROUND = 1,
+    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
+    SP_AUDIO_APP = 3,
+    SP_AUDIO_SYS = 4,
+    SP_TOP_APP = 5,
+    SP_RT_APP = 6,
+    SP_RESTRICTED = 7,
+    SP_CNT,
+    SP_MAX = SP_CNT - 1,
+    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
+} SchedPolicy;
+
+extern int set_cpuset_policy(int tid, SchedPolicy policy);
+
+/* Assign thread tid to the cgroup associated with the specified policy.
+ * If the thread is a thread group leader, that is it's gettid() == getpid(),
+ * then the other threads in the same thread group are _not_ affected.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -errno for error.
+ */
+extern int set_sched_policy(int tid, SchedPolicy policy);
+
+/* Return the policy associated with the cgroup of thread tid via policy pointer.
+ * On platforms which support gettid(), zero tid means current thread.
+ * Return value: 0 for success, or -1 for error and set errno.
+ */
+extern int get_sched_policy(int tid, SchedPolicy *policy);
+
+/* Return a displayable string corresponding to policy.
+ * Return value: non-NULL NUL-terminated name of unspecified length;
+ * the caller is responsible for displaying the useful part of the string.
+ */
+extern const char *get_sched_policy_name(SchedPolicy policy);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* __CUTILS_SCHED_POLICY_H */ 
diff --git a/libprocessgroup/sched_policy.cpp b/libcutils/sched_policy.cpp
similarity index 99%
rename from libprocessgroup/sched_policy.cpp
rename to libcutils/sched_policy.cpp
index f95d7e4..3fa548f 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -14,7 +14,7 @@
 ** limitations under the License.
 */
 
-#include <processgroup/sched_policy.h>
+#include <cutils/sched_policy.h>
 
 #define LOG_TAG "SchedPolicy"
 
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
index 72ae559..7884190 100644
--- a/libcutils/tests/Android.bp
+++ b/libcutils/tests/Android.bp
@@ -59,7 +59,6 @@
     "libcutils",
     "liblog",
     "libbase",
-    "libprocessgroup",
 ]
 
 cc_test {
diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h
index 450a469..8388920 100644
--- a/libmeminfo/include/meminfo/sysmeminfo.h
+++ b/libmeminfo/include/meminfo/sysmeminfo.h
@@ -58,7 +58,7 @@
     // in vmalloc area by the kernel.
     // Note that this deliberately ignores binder buffers. They are _always_
     // mapped in a process and are counted for in each process.
-    uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+    uint64_t ReadVmallocInfo();
 
     // getters
     uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
@@ -84,5 +84,10 @@
                      std::function<void(const std::string&, uint64_t)> store_val);
 };
 
+// Parse /proc/vmallocinfo and return total physical memory mapped
+// in vmalloc area by the kernel. Note that this deliberately ignores binder buffers. They are
+// _always_ mapped in a process and are counted for in each process.
+uint64_t ReadVmallocInfo(const std::string& path = "/proc/vmallocinfo");
+
 }  // namespace meminfo
 }  // namespace android
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 81fc3b3..d88919b 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -455,8 +455,7 @@
     std::string vmallocinfo =
             ::android::base::StringPrintf("%s/testdata1/vmallocinfo", exec_dir.c_str());
     for (auto _ : state) {
-        SysMemInfo smi;
-        CHECK_EQ(smi.ReadVmallocInfo(vmallocinfo), 29884416);
+        CHECK_EQ(::android::meminfo::ReadVmallocInfo(vmallocinfo), 29884416);
     }
 }
 BENCHMARK(BM_VmallocInfo_new);
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 0e0212f..ccc40d1 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -861,8 +861,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    SysMemInfo smi;
-    EXPECT_EQ(smi.ReadVmallocInfo(file), 0);
+    EXPECT_EQ(ReadVmallocInfo(file), 0);
 }
 
 TEST(SysMemInfoParser, TestVmallocInfoKernel) {
@@ -874,8 +873,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    SysMemInfo smi;
-    EXPECT_EQ(smi.ReadVmallocInfo(file), getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file), getpagesize());
 }
 
 TEST(SysMemInfoParser, TestVmallocInfoModule) {
@@ -887,8 +885,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    SysMemInfo smi;
-    EXPECT_EQ(smi.ReadVmallocInfo(file), 6 * getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file), 6 * getpagesize());
 }
 
 TEST(SysMemInfoParser, TestVmallocInfoAll) {
@@ -905,8 +902,7 @@
     ASSERT_TRUE(::android::base::WriteStringToFd(vmallocinfo, tf.fd));
     std::string file = std::string(tf.path);
 
-    SysMemInfo smi;
-    EXPECT_EQ(smi.ReadVmallocInfo(file), 7 * getpagesize());
+    EXPECT_EQ(ReadVmallocInfo(file), 7 * getpagesize());
 }
 
 int main(int argc, char** argv) {
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 8fd18d0..5cfa6c3 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -79,36 +79,8 @@
     });
 }
 
-uint64_t SysMemInfo::ReadVmallocInfo(const std::string& path) {
-    uint64_t vmalloc_total = 0;
-    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
-    if (fp == nullptr) {
-        return vmalloc_total;
-    }
-
-    char line[1024];
-    while (fgets(line, 1024, fp.get()) != nullptr) {
-        // We are looking for lines like
-        // 0x0000000000000000-0x0000000000000000   12288 drm_property_create_blob+0x44/0xec pages=2
-        // vmalloc 0x0000000000000000-0x0000000000000000    8192
-        // wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc Notice that if the caller is
-        // coming from a module, the kernel prints and extra "[module_name]" after the address and
-        // the symbol of the call site. This means we can't use the old sscanf() method of getting
-        // the # of pages.
-        char* p_start = strstr(line, "pages=");
-        if (p_start == nullptr) {
-            // we didn't find anything
-            continue;
-        }
-
-        p_start = strtok(p_start, " ");
-        long nr_pages;
-        if (sscanf(p_start, "pages=%ld", &nr_pages) == 1) {
-            vmalloc_total += (nr_pages * getpagesize());
-        }
-    }
-
-    return vmalloc_total;
+uint64_t SysMemInfo::ReadVmallocInfo() {
+    return ::android::meminfo::ReadVmallocInfo();
 }
 
 // TODO: Delete this function if it can't match up with the c-like implementation below.
@@ -263,5 +235,41 @@
     return false;
 }
 
+// Public methods
+uint64_t ReadVmallocInfo(const std::string& path) {
+    uint64_t vmalloc_total = 0;
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (fp == nullptr) {
+        return vmalloc_total;
+    }
+
+    char* line = nullptr;
+    size_t line_alloc = 0;
+    while (getline(&line, &line_alloc, fp.get()) > 0) {
+        // We are looking for lines like
+        //
+        // 0x0000000000000000-0x0000000000000000   12288 drm_property_create_blob+0x44/0xec pages=2 vmalloc
+        // 0x0000000000000000-0x0000000000000000    8192 wlan_logging_sock_init_svc+0xf8/0x4f0 [wlan] pages=1 vmalloc
+        //
+        // Notice that if the caller is coming from a module, the kernel prints and extra
+        // "[module_name]" after the address and the symbol of the call site. This means we can't
+        // use the old sscanf() method of getting the # of pages.
+        char* p_start = strstr(line, "pages=");
+        if (p_start == nullptr) {
+            // we didn't find anything
+            continue;
+        }
+
+        uint64_t nr_pages;
+        if (sscanf(p_start, "pages=%" SCNu64 "", &nr_pages) == 1) {
+            vmalloc_total += (nr_pages * getpagesize());
+        }
+    }
+
+    free(line);
+
+    return vmalloc_total;
+}
+
 }  // namespace meminfo
 }  // namespace android
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index ab17b29..ad967db 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -43,10 +43,6 @@
 #include <android-base/properties.h>
 #endif
 
-extern "C" {
-struct android_namespace_t* android_get_exported_namespace(const char*);
-}
-
 #define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
                                              "%s:%d: %s CHECK '" #predicate "' failed.",\
                                              __FILE__, __LINE__, __FUNCTION__)
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index d04a79a..c38279d 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -1,45 +1,10 @@
-cc_library_headers {
-    name: "libprocessgroup_headers",
-    vendor_available: true,
-    recovery_available: true,
-    host_supported: true,
-    export_include_dirs: ["include"],
-    target: {
-        linux_bionic: {
-            enabled: true,
-        },
-        windows: {
-            enabled: true,
-        },
-    },
-}
-
 cc_library {
-    srcs: [
-        "processgroup.cpp",
-        "sched_policy.cpp",
-    ],
+    srcs: ["processgroup.cpp"],
     name: "libprocessgroup",
     host_supported: true,
     recovery_available: true,
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-    // for cutils/android_filesystem_config.h
-    header_libs: [
-        "libcutils_headers",
-        "libprocessgroup_headers",
-    ],
+    shared_libs: ["libbase"],
     export_include_dirs: ["include"],
-    export_header_lib_headers: [
-        "libprocessgroup_headers",
-    ],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
deleted file mode 100644
index 79a32fd..0000000
--- a/libprocessgroup/include/processgroup/sched_policy.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Check if Linux kernel enables CPUSETS feature.
- *
- * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise.
- */
-extern bool cpusets_enabled();
-
-/*
- * Check if Linux kernel enables SCHEDTUNE feature (only available in Android
- * common kernel or Linaro LSK, not in mainline Linux as of v4.9)
- *
- * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise.
- */
-extern bool schedboost_enabled();
-
-/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */
-typedef enum {
-    SP_DEFAULT = -1,
-    SP_BACKGROUND = 0,
-    SP_FOREGROUND = 1,
-    SP_SYSTEM = 2,  // can't be used with set_sched_policy()
-    SP_AUDIO_APP = 3,
-    SP_AUDIO_SYS = 4,
-    SP_TOP_APP = 5,
-    SP_RT_APP = 6,
-    SP_RESTRICTED = 7,
-    SP_CNT,
-    SP_MAX = SP_CNT - 1,
-    SP_SYSTEM_DEFAULT = SP_FOREGROUND,
-} SchedPolicy;
-
-extern int set_cpuset_policy(int tid, SchedPolicy policy);
-
-/* Assign thread tid to the cgroup associated with the specified policy.
- * If the thread is a thread group leader, that is it's gettid() == getpid(),
- * then the other threads in the same thread group are _not_ affected.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -errno for error.
- */
-extern int set_sched_policy(int tid, SchedPolicy policy);
-
-/* Return the policy associated with the cgroup of thread tid via policy pointer.
- * On platforms which support gettid(), zero tid means current thread.
- * Return value: 0 for success, or -1 for error and set errno.
- */
-extern int get_sched_policy(int tid, SchedPolicy *policy);
-
-/* Return a displayable string corresponding to policy.
- * Return value: non-NULL NUL-terminated name of unspecified length;
- * the caller is responsible for displaying the useful part of the string.
- */
-extern const char *get_sched_policy_name(SchedPolicy policy);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 8d2ac3d..9df8dd9 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -42,7 +42,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <cutils/android_filesystem_config.h>
+#include <private/android_filesystem_config.h>
 
 #include <processgroup/processgroup.h>
 
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index a91bd95..c747eab 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -47,6 +47,7 @@
 enum TestTypeEnum : uint8_t {
   TEST_TYPE_LOCAL_UNWINDER = 0,
   TEST_TYPE_LOCAL_UNWINDER_FROM_PID,
+  TEST_TYPE_LOCAL_WAIT_FOR_FINISH,
   TEST_TYPE_REMOTE,
   TEST_TYPE_REMOTE_WITH_INVALID_CALL,
 };
@@ -79,7 +80,10 @@
 
 extern "C" void SignalInnerFunction() {
   g_signal_ready_for_remote = true;
-  while (!g_finish.load()) {
+  // Avoid any function calls because not every instruction will be
+  // unwindable.
+  // This method of looping is only used when testing a remote unwind.
+  while (true) {
   }
 }
 
@@ -134,6 +138,11 @@
 // off. If this doesn't happen, then all of the calls will be optimized
 // away.
 extern "C" void InnerFunction(TestTypeEnum test_type) {
+  if (test_type == TEST_TYPE_LOCAL_WAIT_FOR_FINISH) {
+    while (!g_finish.load()) {
+    }
+    return;
+  }
   if (test_type == TEST_TYPE_REMOTE || test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
     g_ready_for_remote = true;
     g_ready = true;
@@ -141,7 +150,10 @@
       void (*crash_func)() = nullptr;
       crash_func();
     }
-    while (!g_finish.load()) {
+    // Avoid any function calls because not every instruction will be
+    // unwindable.
+    // This method of looping is only used when testing a remote unwind.
+    while (true) {
     }
     return;
   }
@@ -271,7 +283,7 @@
   std::atomic_int tid(0);
   std::thread thread([&]() {
     tid = syscall(__NR_gettid);
-    OuterFunction(TEST_TYPE_REMOTE);
+    OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
   });
 
   struct sigaction act, oldact;
diff --git a/libutils/Android.bp b/libutils/Android.bp
index fb7ca32..3e8417e 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -22,13 +22,11 @@
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
-        "libprocessgroup_headers",
     ],
     export_header_lib_headers: [
         "liblog_headers",
         "libsystem_headers",
         "libcutils_headers",
-        "libprocessgroup_headers",
     ],
     export_include_dirs: ["include"],
 
@@ -84,7 +82,6 @@
 
             shared_libs: [
                 "libcutils",
-                "libprocessgroup",
                 "libdl",
                 "libvndksupport",
             ],
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 31ca138..64bc402 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -36,7 +36,7 @@
 
 #include <utils/Log.h>
 
-#include <processgroup/sched_policy.h>
+#include <cutils/sched_policy.h>
 
 #if defined(__ANDROID__)
 # define __android_unused
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index f9ed57c..903d0e2 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -5,7 +5,6 @@
     shared_libs: [
         "libcutils",
         "liblog",
-        "libprocessgroup",
     ],
     static_libs: [
         "libstatslogc",
diff --git a/logcat/Android.bp b/logcat/Android.bp
index 5030b15..0543aba 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -24,8 +24,8 @@
     ],
     shared_libs: [
         "libbase",
+        "libcutils",
         "libpcrecpp",
-        "libprocessgroup",
     ],
     static_libs: ["liblog"],
     logtags: ["event.logtags"],
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 15e07fe..87bc6ae 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -49,11 +49,11 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <log/logprint.h>
 #include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
 #include <system/thread_defs.h>
 
 #include <pcrecpp.h>
diff --git a/logd/Android.bp b/logd/Android.bp
index bdbdf12..3abfc21 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -73,7 +73,6 @@
         "libcutils",
         "libbase",
         "libpackagelistparser",
-        "libprocessgroup",
         "libcap",
     ],
 
diff --git a/logd/main.cpp b/logd/main.cpp
index fd3cdf8..8c38d9a 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -38,12 +38,12 @@
 #include <android-base/macros.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/properties.h>
+#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
diff --git a/mkbootimg/include/bootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h
index 4432f9e..9ee7869 100644
--- a/mkbootimg/include/bootimg/bootimg.h
+++ b/mkbootimg/include/bootimg/bootimg.h
@@ -115,7 +115,7 @@
     uint32_t header_size;
 } __attribute__((packed));
 
-/* When the boot image header has a version of 1, the structure of the boot
+/* When the boot image header has a version of 2, the structure of the boot
  * image is as follows:
  *
  * +---------------------+
@@ -129,17 +129,21 @@
  * +---------------------+
  * | recovery dtbo/acpio | p pages
  * +---------------------+
+ * | dtb                 | q pages
+ * +---------------------+
+
  * n = (kernel_size + page_size - 1) / page_size
  * m = (ramdisk_size + page_size - 1) / page_size
  * o = (second_size + page_size - 1) / page_size
  * p = (recovery_dtbo_size + page_size - 1) / page_size
+ * q = (dtb_size + page_size - 1) / page_size
  *
  * 0. all entities are page_size aligned in flash
- * 1. kernel and ramdisk are required (size != 0)
+ * 1. kernel, ramdisk and DTB are required (size != 0)
  * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
  *    devices(recovery_dtbo_size != 0)
  * 3. second is optional (second_size == 0 -> no second)
- * 4. load each element (kernel, ramdisk, second) at
+ * 4. load each element (kernel, ramdisk, second, dtb) at
  *    the specified physical address (kernel_addr, etc)
  * 5. If booting to recovery mode in a non-A/B device, extract recovery
  *    dtbo/acpio and apply the correct set of overlays on the base device tree
@@ -150,3 +154,7 @@
  * 8. if second_size != 0: jump to second_addr
  *    else: jump to kernel_addr
  */
+struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
+    uint32_t dtb_size; /* size in bytes for DTB image */
+    uint64_t dtb_addr; /* physical load address for DTB image */
+} __attribute__((packed));
diff --git a/mkbootimg/mkbootimg.py b/mkbootimg/mkbootimg.py
index 2eb2bab..859b1e4 100644
--- a/mkbootimg/mkbootimg.py
+++ b/mkbootimg/mkbootimg.py
@@ -85,6 +85,8 @@
 
     if args.header_version > 0:
         update_sha(sha, args.recovery_dtbo)
+    if args.header_version > 1:
+        update_sha(sha, args.dtb)
 
     img_id = pack('32s', sha.digest())
 
@@ -99,6 +101,10 @@
             args.output.write(pack('Q', 0)) # Will be set to 0 for devices without a recovery dtbo
         args.output.write(pack('I', args.output.tell() + 4))         # size of boot header
 
+
+    if args.header_version > 1:
+        args.output.write(pack('I', filesize(args.dtb)))   # size in bytes
+        args.output.write(pack('Q', args.base + args.dtb_offset)) # dtb physical load address
     pad_file(args.output, args.pagesize)
     return img_id
 
@@ -161,6 +167,7 @@
                         required=True)
     parser.add_argument('--ramdisk', help='path to the ramdisk', type=FileType('rb'))
     parser.add_argument('--second', help='path to the 2nd bootloader', type=FileType('rb'))
+    parser.add_argument('--dtb', help='path to dtb', type=FileType('rb'))
     recovery_dtbo_group = parser.add_mutually_exclusive_group()
     recovery_dtbo_group.add_argument('--recovery_dtbo', help='path to the recovery DTBO', type=FileType('rb'))
     recovery_dtbo_group.add_argument('--recovery_acpio', help='path to the recovery ACPIO',
@@ -172,6 +179,8 @@
     parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
     parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
                         default=0x00f00000)
+    parser.add_argument('--dtb_offset', help='dtb offset', type=parse_int, default=0x01f00000)
+
     parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
                         default=0)
     parser.add_argument('--os_patch_level', help='operating system patch level',
@@ -196,6 +205,8 @@
 
     if args.header_version > 0:
         write_padded_file(args.output, args.recovery_dtbo, args.pagesize)
+    if args.header_version > 1:
+        write_padded_file(args.output, args.dtb, args.pagesize)
 
 def main():
     args = parse_cmdline()
diff --git a/mkbootimg/unpack_bootimg.py b/mkbootimg/unpack_bootimg.py
old mode 100644
new mode 100755
index c37acd5..6b5d5d0
--- a/mkbootimg/unpack_bootimg.py
+++ b/mkbootimg/unpack_bootimg.py
@@ -15,7 +15,7 @@
 
 """unpacks the bootimage.
 
-Extracts the kernel, ramdisk, second bootloader and recovery dtbo images.
+Extracts the kernel, ramdisk, second bootloader, dtb and recovery dtbo images.
 """
 
 from __future__ import print_function
@@ -82,6 +82,14 @@
         print('boot header size: %s' % boot_header_size)
     else:
         recovery_dtbo_size = 0
+    if version > 1:
+        dtb_size = unpack('I', args.boot_img.read(4))[0]
+        print('dtb size: %s' % dtb_size)
+        dtb_load_address = unpack('Q', args.boot_img.read(8))[0]
+        print('dtb address: %s' % dtb_load_address)
+    else:
+        dtb_size = 0
+
 
     # The first page contains the boot header
     num_header_pages = 1
@@ -103,6 +111,15 @@
     if recovery_dtbo_size > 0:
         image_info_list.append((recovery_dtbo_offset, recovery_dtbo_size,
                                 'recovery_dtbo'))
+    if dtb_size > 0:
+        num_second_pages = get_number_of_pages(second_size, page_size)
+        num_recovery_dtbo_pages = get_number_of_pages(recovery_dtbo_size, page_size)
+        dtb_offset = page_size * (
+            num_header_pages + num_kernel_pages + num_ramdisk_pages + num_second_pages +
+            num_recovery_dtbo_pages
+        )
+
+        image_info_list.append((dtb_offset, dtb_size, 'dtb'))
 
     for image_info in image_info_list:
         extract_image(image_info[0], image_info[1], args.boot_img,
@@ -113,7 +130,7 @@
     """parse command line arguments"""
     parser = ArgumentParser(
         description='Unpacks boot.img/recovery.img, extracts the kernel,'
-        'ramdisk, second bootloader and recovery dtbo')
+        'ramdisk, second bootloader, recovery dtbo and dtb')
     parser.add_argument(
         '--boot_img',
         help='path to boot image',
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 85c7e9e..1871ca7 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -129,6 +129,19 @@
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/priv-app $(TARGET_ROOT_OUT)/odm/priv-app
 LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/odm/usr $(TARGET_ROOT_OUT)/odm/usr
 
+# Start of runtime APEX compatibility.
+# Keeping the appearance of files/dirs having old locations for apps that have
+# come to rely on them.
+
+# http://b/121248172 - create a link from /system/usr/icu to
+# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file.
+# A symlink can't overwrite a directory and the /system/usr/icu directory once
+# existed so the required structure must be created whatever we find.
+LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
+LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu
+
+# End of runtime APEX compatibilty.
+
 ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
   LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache
 else
@@ -253,14 +266,11 @@
 include $(LOCAL_PATH)/update_and_install_ld_config.mk
 endef
 
-# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the
-# prebuilt under /prebuilts/vndk
 vndk_snapshots := $(wildcard prebuilts/vndk/*)
 supported_vndk_snapshot_versions := \
-  $(strip $(foreach ver,$(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)),\
-    $(if $(call math_gt_or_eq,$(ver),28),$(ver),)))
-$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\
-  $(call build_versioned_ld_config,$(ver))))
+  $(strip $(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)))
+$(foreach ver,$(supported_vndk_snapshot_versions),\
+  $(eval $(call build_versioned_ld_config,$(ver))))
 
 vndk_snapshots :=
 supported_vndk_snapshot_versions :=
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 3804c86..1d4b1e2 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -109,7 +109,11 @@
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
 namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativebridge.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
@@ -152,11 +156,12 @@
 namespace.conscrypt.isolated = true
 namespace.conscrypt.visible = true
 
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
-namespace.conscrypt.link.default.allow_all_shared_libs = true
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
 
 ###############################################################################
 # "sphal" namespace
@@ -310,7 +315,7 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-additional.namespaces = system,vndk
+additional.namespaces = runtime,system,vndk
 
 ###############################################################################
 # "default" namespace
@@ -347,6 +352,20 @@
 namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
 
 ###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = system
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.system.allow_all_shared_libs = true
+
+###############################################################################
 # "vndk" namespace
 #
 # This namespace is where VNDK and VNDK-SP libraries are loaded for
@@ -403,6 +422,9 @@
 namespace.system.asan.search.paths += /data/asan/product_services/${LIB}
 namespace.system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
+namespace.system.links = runtime
+namespace.system.link.runtime.shared_libs = libdexfile_external.so
+
 ###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only default namespace is defined and default has no directories
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 2ce25b5..d54156b 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -55,9 +55,14 @@
 namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the platform namespace in the com.android.runtime APEX
+# ld.config.txt.
 namespace.default.links = runtime
+# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
+# libart.
+namespace.default.visible = true
 namespace.default.link.runtime.shared_libs  = libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libnativehelper.so
 namespace.default.link.runtime.shared_libs += libnativeloader.so
 
@@ -68,7 +73,8 @@
 ###############################################################################
 namespace.runtime.isolated = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the default namespace in the com.android.runtime APEX
+# ld.config.txt.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
 # TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
@@ -99,11 +105,12 @@
 namespace.conscrypt.isolated = true
 namespace.conscrypt.visible = true
 
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = default
-# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
-# when it exists.
-namespace.conscrypt.link.default.allow_all_shared_libs = true
+namespace.conscrypt.link.default.shared_libs  = libc.so
+namespace.conscrypt.link.default.shared_libs += libm.so
+namespace.conscrypt.link.default.shared_libs += libdl.so
 
 ###############################################################################
 # "sphal" namespace
@@ -251,6 +258,8 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
+additional.namespaces = runtime
+
 namespace.default.isolated = false
 
 namespace.default.search.paths  = /odm/${LIB}
@@ -290,6 +299,23 @@
 namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libdexfile_external.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
 ###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only default namespace is defined and default has no directories
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 2e95687..e8c5d8e 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -4,6 +4,7 @@
     user root
     group root readproc reserved_disk
     socket zygote stream 660 root system
+    socket blastula_pool stream 660 root system
     updatable
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1cfc3d6..9c7e807 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -4,6 +4,7 @@
     user root
     group root readproc reserved_disk
     socket zygote stream 660 root system
+    socket blastula_pool stream 660 root system
     updatable
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -20,6 +21,7 @@
     user root
     group root readproc reserved_disk
     socket zygote_secondary stream 660 root system
+    socket blastula_pool_secondary stream 660 root system
     updatable
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 8ab012d..9908c99 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -4,6 +4,7 @@
     user root
     group root readproc reserved_disk
     socket zygote stream 660 root system
+    socket blastula_pool stream 660 root system
     updatable
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 5abf149..0b5edff 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -4,6 +4,7 @@
     user root
     group root readproc reserved_disk
     socket zygote stream 660 root system
+    socket blastula_pool stream 660 root system
     updatable
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
@@ -20,6 +21,7 @@
     user root
     group root readproc reserved_disk
     socket zygote_secondary stream 660 root system
+    socket blastula_pool_secondary stream 660 root system
     updatable
     onrestart restart zygote
     writepid /dev/cpuset/foreground/tasks