Merge "Add simpleperf in system shell utilities."
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index eda4b77..9a25d10 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -144,53 +144,51 @@
     }
 
     std::string reason;
-    int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
-    if (fd < 0) {
+    unique_fd fd;
+    if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) {
         *error = android::base::StringPrintf("cannot connect to daemon at %s: %s",
                                              __adb_server_socket_spec, reason.c_str());
         return -2;
     }
 
-    if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd, error)) {
+    if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd.get(), error)) {
         return -1;
     }
 
-    if (!SendProtocolString(fd, service)) {
+    if (!SendProtocolString(fd.get(), service)) {
         *error = perror_str("write failure during connection");
-        adb_close(fd);
         return -1;
     }
 
-    if (!adb_status(fd, error)) {
-        adb_close(fd);
+    if (!adb_status(fd.get(), error)) {
         return -1;
     }
 
-    D("_adb_connect: return fd %d", fd);
-    return fd;
+    D("_adb_connect: return fd %d", fd.get());
+    return fd.release();
 }
 
 bool adb_kill_server() {
     D("adb_kill_server");
     std::string reason;
-    int fd = socket_spec_connect(__adb_server_socket_spec, &reason);
-    if (fd < 0) {
+    unique_fd fd;
+    if (!socket_spec_connect(&fd, __adb_server_socket_spec, nullptr, nullptr, &reason)) {
         fprintf(stderr, "cannot connect to daemon at %s: %s\n", __adb_server_socket_spec,
                 reason.c_str());
         return true;
     }
 
-    if (!SendProtocolString(fd, "host:kill")) {
+    if (!SendProtocolString(fd.get(), "host:kill")) {
         fprintf(stderr, "error: write failure during connection: %s\n", strerror(errno));
         return false;
     }
 
     // The server might send OKAY, so consume that.
     char buf[4];
-    ReadFdExactly(fd, buf, 4);
+    ReadFdExactly(fd.get(), buf, 4);
     // Now that no more data is expected, wait for socket orderly shutdown or error, indicating
     // server death.
-    ReadOrderlyShutdown(fd);
+    ReadOrderlyShutdown(fd.get());
     return true;
 }
 
diff --git a/adb/fastdeploy/Android.bp b/adb/fastdeploy/Android.bp
index 400b12f..1ba0de0 100644
--- a/adb/fastdeploy/Android.bp
+++ b/adb/fastdeploy/Android.bp
@@ -22,6 +22,9 @@
     wrapper: "deployagent/deployagent.sh",
     proto: {
         type: "lite",
+    },
+    dex_preopt: {
+        enabled: false,
     }
 }
 
diff --git a/adb/services.cpp b/adb/services.cpp
index 8636657..73fed09 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -72,24 +72,23 @@
 }
 
 int service_to_fd(std::string_view name, atransport* transport) {
-    int ret = -1;
+    unique_fd ret;
 
     if (is_socket_spec(name)) {
         std::string error;
-        ret = socket_spec_connect(name, &error);
-        if (ret < 0) {
+        if (!socket_spec_connect(&ret, name, nullptr, nullptr, &error)) {
             LOG(ERROR) << "failed to connect to socket '" << name << "': " << error;
         }
     } else {
 #if !ADB_HOST
-        ret = daemon_service_to_fd(name, transport).release();
+        ret = daemon_service_to_fd(name, transport);
 #endif
     }
 
     if (ret >= 0) {
         close_on_exec(ret);
     }
-    return ret;
+    return ret.release();
 }
 
 #if ADB_HOST
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 4cddc84..cc67b6b 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -67,7 +67,7 @@
 });
 
 bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port,
-                           std::string* error) {
+                           std::string* serial, std::string* error) {
     if (!spec.starts_with("tcp:")) {
         *error = "specification is not tcp: ";
         *error += spec;
@@ -92,7 +92,7 @@
 
         // FIXME: ParseNetAddress rejects port 0. This currently doesn't hurt, because listening
         //        on an address that isn't 'localhost' is unsupported.
-        if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, nullptr, error)) {
+        if (!android::base::ParseNetAddress(addr, &hostname_value, &port_value, serial, error)) {
             return false;
         }
 
@@ -139,63 +139,68 @@
 
     std::string error;
     std::string hostname;
-    if (!parse_tcp_socket_spec(spec, &hostname, nullptr, &error)) {
+    if (!parse_tcp_socket_spec(spec, &hostname, nullptr, nullptr, &error)) {
         return false;
     }
     return tcp_host_is_local(hostname);
 }
 
-int socket_spec_connect(std::string_view spec, std::string* error) {
-    if (spec.starts_with("tcp:")) {
+bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial,
+                         std::string* error) {
+    if (address.starts_with("tcp:")) {
         std::string hostname;
-        int port;
-        if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
-            return -1;
+        int port_value = port ? *port : 0;
+        if (!parse_tcp_socket_spec(address, &hostname, &port_value, serial, error)) {
+            return false;
         }
 
-        int result;
         if (tcp_host_is_local(hostname)) {
-            result = network_loopback_client(port, SOCK_STREAM, error);
+            fd->reset(network_loopback_client(port_value, SOCK_STREAM, error));
         } else {
 #if ADB_HOST
-            result = network_connect(hostname, port, SOCK_STREAM, 0, error);
+            fd->reset(network_connect(hostname, port_value, SOCK_STREAM, 0, error));
 #else
             // Disallow arbitrary connections in adbd.
             *error = "adbd does not support arbitrary tcp connections";
-            return -1;
+            return false;
 #endif
         }
 
-        if (result >= 0) {
-            disable_tcp_nagle(result);
+        if (fd->get() > 0) {
+            disable_tcp_nagle(fd->get());
+            if (port) {
+                *port = port_value;
+            }
+            return true;
         }
-        return result;
+        return false;
     }
 
     for (const auto& it : kLocalSocketTypes) {
         std::string prefix = it.first + ":";
-        if (spec.starts_with(prefix)) {
+        if (address.starts_with(prefix)) {
             if (!it.second.available) {
                 *error = StringPrintf("socket type %s is unavailable on this platform",
                                       it.first.c_str());
-                return -1;
+                return false;
             }
 
-            return network_local_client(&spec[prefix.length()], it.second.socket_namespace,
-                                        SOCK_STREAM, error);
+            fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
+                                           SOCK_STREAM, error));
+            return true;
         }
     }
 
     *error = "unknown socket specification: ";
-    *error += spec;
-    return -1;
+    *error += address;
+    return false;
 }
 
 int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port) {
     if (spec.starts_with("tcp:")) {
         std::string hostname;
         int port;
-        if (!parse_tcp_socket_spec(spec, &hostname, &port, error)) {
+        if (!parse_tcp_socket_spec(spec, &hostname, &port, nullptr, error)) {
             return -1;
         }
 
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
index 5b06973..687d751 100644
--- a/adb/socket_spec.h
+++ b/adb/socket_spec.h
@@ -17,14 +17,18 @@
 #pragma once
 
 #include <string>
+#include <tuple>
+
+#include "adb_unique_fd.h"
 
 // Returns true if the argument starts with a plausible socket prefix.
 bool is_socket_spec(std::string_view spec);
 bool is_local_socket_spec(std::string_view spec);
 
-int socket_spec_connect(std::string_view spec, std::string* error);
+bool socket_spec_connect(unique_fd* fd, std::string_view address, int* port, std::string* serial,
+                         std::string* error);
 int socket_spec_listen(std::string_view spec, std::string* error, int* resolved_tcp_port = nullptr);
 
 // Exposed for testing.
 bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port,
-                           std::string* error);
+                           std::string* serial, std::string* error);
diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp
index 40ce21c..f5ec0f1 100644
--- a/adb/socket_spec_test.cpp
+++ b/adb/socket_spec_test.cpp
@@ -21,34 +21,37 @@
 #include <gtest/gtest.h>
 
 TEST(socket_spec, parse_tcp_socket_spec) {
-    std::string hostname, error;
+    std::string hostname, error, serial;
     int port;
-    EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &error));
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:5037", &hostname, &port, &serial, &error));
     EXPECT_EQ("", hostname);
     EXPECT_EQ(5037, port);
+    EXPECT_EQ("", serial);
 
     // Bad ports:
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:-1", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:65536", &hostname, &port, &serial, &error));
 
-    EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &error));
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:localhost:1234", &hostname, &port, &serial, &error));
     EXPECT_EQ("localhost", hostname);
     EXPECT_EQ(1234, port);
+    EXPECT_EQ("localhost:1234", serial);
 
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:-1", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:localhost:65536", &hostname, &port, &serial, &error));
 
     // IPv6:
-    EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &error));
+    EXPECT_TRUE(parse_tcp_socket_spec("tcp:[::1]:1234", &hostname, &port, &serial, &error));
     EXPECT_EQ("::1", hostname);
     EXPECT_EQ(1234, port);
+    EXPECT_EQ("[::1]:1234", serial);
 
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &error));
-    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1", &hostname, &port, &serial, &error));
+    EXPECT_FALSE(parse_tcp_socket_spec("tcp:::1:1234", &hostname, &port, &serial, &error));
 }
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index dc87ac7..b384085 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -45,6 +45,7 @@
 #include "adb_io.h"
 #include "adb_unique_fd.h"
 #include "adb_utils.h"
+#include "socket_spec.h"
 #include "sysdeps/chrono.h"
 
 #if ADB_HOST
@@ -70,32 +71,17 @@
 
 std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
                                                     std::string* response) {
-    std::string serial;
-    std::string host;
+    unique_fd fd;
     int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    if (!android::base::ParseNetAddress(address, &host, &port, &serial, response)) {
-        D("failed to parse address: '%s'", address.c_str());
-        return std::make_tuple(unique_fd(), port, serial);
-    }
-
-    std::string error;
-    unique_fd fd(network_connect(host.c_str(), port, SOCK_STREAM, 10, &error));
-    if (fd == -1) {
-        *response = android::base::StringPrintf("unable to connect to %s: %s",
-                                                serial.c_str(), error.c_str());
+    std::string serial;
+    if (socket_spec_connect(&fd, "tcp:" + address, &port, &serial, response)) {
+        close_on_exec(fd);
+        if (!set_tcp_keepalive(fd, 1)) {
+            D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
+        }
         return std::make_tuple(std::move(fd), port, serial);
     }
-
-    D("client: connected %s remote on fd %d", serial.c_str(), fd.get());
-    close_on_exec(fd);
-    disable_tcp_nagle(fd);
-
-    // Send a TCP keepalive ping to the device every second so we can detect disconnects.
-    if (!set_tcp_keepalive(fd, 1)) {
-        D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
-    }
-
-    return std::make_tuple(std::move(fd), port, serial);
+    return std::make_tuple(unique_fd(), 0, "");
 }
 
 void connect_device(const std::string& address, std::string* response) {
@@ -251,8 +237,9 @@
     adb_thread_setname("server socket");
     D("transport: server_socket_thread() starting");
     while (serverfd == -1) {
+        std::string spec = android::base::StringPrintf("tcp:%d", port);
         std::string error;
-        serverfd.reset(network_inaddr_any_server(port, SOCK_STREAM, &error));
+        serverfd.reset(socket_spec_listen(spec, &error));
         if (serverfd < 0) {
             D("server: cannot bind socket yet: %s", error.c_str());
             std::this_thread::sleep_for(1s);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 19445c8..70a1045 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -79,6 +79,7 @@
 
 #define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
 #define ZRAM_CONF_MCS   "/sys/block/zram0/max_comp_streams"
+#define ZRAM_BACK_DEV   "/sys/block/zram0/backing_dev"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
 
@@ -1373,6 +1374,70 @@
     return 0;
 }
 
+static bool InstallZramDevice(const std::string& device) {
+    if (!android::base::WriteStringToFile(device, ZRAM_BACK_DEV)) {
+        PERROR << "Cannot write " << device << " in: " << ZRAM_BACK_DEV;
+        return false;
+    }
+    LINFO << "Success to set " << device << " to " << ZRAM_BACK_DEV;
+    return true;
+}
+
+static bool PrepareZramDevice(const std::string& loop, off64_t size, const std::string& bdev) {
+    if (loop.empty() && bdev.empty()) return true;
+
+    if (bdev.length()) {
+        return InstallZramDevice(bdev);
+    }
+
+    // Get free loopback
+    unique_fd loop_fd(TEMP_FAILURE_RETRY(open("/dev/loop-control", O_RDWR | O_CLOEXEC)));
+    if (loop_fd.get() == -1) {
+        PERROR << "Cannot open loop-control";
+        return false;
+    }
+
+    int num = ioctl(loop_fd.get(), LOOP_CTL_GET_FREE);
+    if (num == -1) {
+        PERROR << "Cannot get free loop slot";
+        return false;
+    }
+
+    // Prepare target path
+    unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0664)));
+    if (target_fd.get() == -1) {
+        PERROR << "Cannot open target path: " << loop;
+        return false;
+    }
+    if (fallocate(target_fd.get(), 0, 0, size) < 0) {
+        PERROR << "Cannot truncate target path: " << loop;
+        return false;
+    }
+
+    // Connect loopback (device_fd) to target path (target_fd)
+    std::string device = android::base::StringPrintf("/dev/block/loop%d", num);
+    unique_fd device_fd(TEMP_FAILURE_RETRY(open(device.c_str(), O_RDWR | O_CLOEXEC)));
+    if (device_fd.get() == -1) {
+        PERROR << "Cannot open /dev/block/loop" << num;
+        return false;
+    }
+
+    if (ioctl(device_fd.get(), LOOP_SET_FD, target_fd.get())) {
+        PERROR << "Cannot set loopback to target path";
+        return false;
+    }
+
+    // set block size & direct IO
+    if (ioctl(device_fd.get(), LOOP_SET_BLOCK_SIZE, 4096)) {
+        PWARNING << "Cannot set 4KB blocksize to /dev/block/loop" << num;
+    }
+    if (ioctl(device_fd.get(), LOOP_SET_DIRECT_IO, 1)) {
+        PWARNING << "Cannot set direct_io to /dev/block/loop" << num;
+    }
+
+    return InstallZramDevice(device);
+}
+
 bool fs_mgr_swapon_all(const Fstab& fstab) {
     bool ret = true;
     for (const auto& entry : fstab) {
@@ -1381,6 +1446,10 @@
             continue;
         }
 
+        if (!PrepareZramDevice(entry.zram_loopback_path, entry.zram_loopback_size, entry.zram_backing_dev_path)) {
+            LERROR << "Skipping losetup for '" << entry.blk_device << "'";
+        }
+
         if (entry.zram_size > 0) {
             // A zram_size was specified, so we need to configure the
             // device.  There is no point in having multiple zram devices
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 2576035..c9f34a7 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -28,6 +28,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/parseint.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <libgsi/libgsi.h>
@@ -44,6 +45,9 @@
     std::string key_dir;
     std::string verity_loc;
     std::string sysfs_path;
+    std::string zram_loopback_path;
+    uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default
+    std::string zram_backing_dev_path;
     off64_t part_length = 0;
     std::string label;
     int partnum = -1;
@@ -118,6 +122,9 @@
         {"checkpoint=block", MF_CHECKPOINT_BLK},
         {"checkpoint=fs", MF_CHECKPOINT_FS},
         {"slotselect_other", MF_SLOTSELECT_OTHER},
+        {"zram_loopback_path=", MF_ZRAM_LOOPBACK_PATH},
+        {"zram_loopback_size=", MF_ZRAM_LOOPBACK_SIZE},
+        {"zram_backing_dev_path=", MF_ZRAM_BACKING_DEV_PATH},
         {0, 0},
 };
 
@@ -345,6 +352,16 @@
                 } else if (flag == MF_SYSFS) {
                     /* The path to trigger device gc by idle-maint of vold. */
                     flag_vals->sysfs_path = arg;
+                } else if (flag == MF_ZRAM_LOOPBACK_PATH) {
+                    /* The path to use loopback for zram. */
+                    flag_vals->zram_loopback_path = arg;
+                } else if (flag == MF_ZRAM_LOOPBACK_SIZE) {
+                    if (!android::base::ParseByteCount(arg, &flag_vals->zram_loopback_size)) {
+                        LERROR << "Warning: zram_loopback_size = flag malformed";
+                    }
+                } else if (flag == MF_ZRAM_BACKING_DEV_PATH) {
+                    /* The path to use loopback for zram. */
+                    flag_vals->zram_backing_dev_path = arg;
                 }
                 break;
             }
@@ -570,6 +587,9 @@
         entry.logical_blk_size = flag_vals.logical_blk_size;
         entry.sysfs_path = std::move(flag_vals.sysfs_path);
         entry.vbmeta_partition = std::move(flag_vals.vbmeta_partition);
+        entry.zram_loopback_path = std::move(flag_vals.zram_loopback_path);
+        entry.zram_loopback_size = std::move(flag_vals.zram_loopback_size);
+        entry.zram_backing_dev_path = std::move(flag_vals.zram_backing_dev_path);
         if (entry.fs_mgr_flags.logical) {
             entry.logical_partition_name = entry.blk_device;
         }
@@ -811,6 +831,8 @@
         free(fstab->recs[i].key_dir);
         free(fstab->recs[i].label);
         free(fstab->recs[i].sysfs_path);
+        free(fstab->recs[i].zram_loopback_path);
+        free(fstab->recs[i].zram_backing_dev_path);
     }
 
     /* Free the fstab_recs array created by calloc(3) */
@@ -908,6 +930,9 @@
     entry.erase_blk_size = fstab_rec->erase_blk_size;
     entry.logical_blk_size = fstab_rec->logical_blk_size;
     entry.sysfs_path = fstab_rec->sysfs_path;
+    entry.zram_loopback_path = fstab_rec->zram_loopback_path;
+    entry.zram_loopback_size = fstab_rec->zram_loopback_size;
+    entry.zram_backing_dev_path = fstab_rec->zram_backing_dev_path;
 
     return entry;
 }
@@ -951,6 +976,9 @@
         legacy_fstab->recs[i].erase_blk_size = fstab[i].erase_blk_size;
         legacy_fstab->recs[i].logical_blk_size = fstab[i].logical_blk_size;
         legacy_fstab->recs[i].sysfs_path = strdup(fstab[i].sysfs_path.c_str());
+        legacy_fstab->recs[i].zram_loopback_path = strdup(fstab[i].zram_loopback_path.c_str());
+        legacy_fstab->recs[i].zram_loopback_size = fstab[i].zram_loopback_size;
+        legacy_fstab->recs[i].zram_backing_dev_path = strdup(fstab[i].zram_backing_dev_path.c_str());
     }
     return legacy_fstab;
 }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 7842ca2..39ceff7 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -122,6 +122,12 @@
                           0x80000000
 #define MF_SLOTSELECT_OTHER  \
                          0x100000000
+#define MF_ZRAM_LOOPBACK_PATH    \
+                         0x200000000
+#define MF_ZRAM_LOOPBACK_SIZE    \
+                         0x400000000
+#define MF_ZRAM_BACKING_DEV_PATH \
+                         0x800000000
 // clang-format on
 
 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 6643c0d..5d8496d 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -59,6 +59,9 @@
     off64_t erase_blk_size;
     off64_t logical_blk_size;
     char* sysfs_path;
+    char* zram_loopback_path;
+    uint64_t zram_loopback_size;
+    char* zram_backing_dev_path;
 };
 
 struct fstab* fs_mgr_read_fstab_default();
@@ -119,6 +122,9 @@
     off64_t logical_blk_size = 0;
     std::string sysfs_path;
     std::string vbmeta_partition;
+    std::string zram_loopback_path;
+    uint64_t zram_loopback_size;
+    std::string zram_backing_dev_path;
 
     // TODO: Remove this union once fstab_rec is deprecated. It only serves as a
     // convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 4a0d4b5..71b39a9 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -304,7 +304,6 @@
     return true;
 }
 
-#if 0
 static bool IsFilePinned(int file_fd, const std::string& file_path, uint32_t fs_type) {
     if (fs_type == EXT4_SUPER_MAGIC) {
         // No pinning necessary for ext4. The blocks, once allocated, are expected
@@ -345,7 +344,6 @@
     }
     return moved_blocks_nr == 0;
 }
-#endif
 
 static void LogExtent(uint32_t num, const struct fiemap_extent& ext) {
     LOG(INFO) << "Extent #" << num;
@@ -477,13 +475,15 @@
 
     if (create) {
         if (!AllocateFile(file_fd, abs_path, blocksz, file_size)) {
+            LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
+                       << " bytes";
             cleanup(abs_path, create);
             return nullptr;
         }
     }
 
     // f2fs may move the file blocks around.
-    if (!PinFile(file_fd, file_path, fs_type)) {
+    if (!PinFile(file_fd, abs_path, fs_type)) {
         cleanup(abs_path, create);
         LOG(ERROR) << "Failed to pin the file in storage";
         return nullptr;
@@ -538,13 +538,11 @@
         return false;
     }
 
-#if 0
-    // TODO(b/122138114): check why this fails.
     if (!IsFilePinned(file_fd_, file_path_, fs_type_)) {
         LOG(ERROR) << "Failed write: file " << file_path_ << " is not pinned";
         return false;
     }
-#endif
+
     // find extents that must be written to and then write one at a time.
     uint32_t num_extent = 1;
     uint32_t buffer_offset = 0;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 825109f..0765f04 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -164,12 +164,26 @@
 
 Returns: true if device in root state" ]
 adb_root() {
+  [ `adb_sh echo '${USER}'` != root ] || return 0
   adb root >/dev/null </dev/null 2>/dev/null
   sleep 2
   adb_wait 2m &&
     [ `adb_sh echo '${USER}'` = root ]
 }
 
+[ "USAGE: adb_unroot
+
+NB: This can be flakey on devices due to USB state
+
+Returns: true if device in un root state" ]
+adb_unroot() {
+  [ `adb_sh echo '${USER}'` = root ] || return 0
+  adb unroot >/dev/null </dev/null 2>/dev/null
+  sleep 2
+  adb_wait 2m &&
+    [ `adb_sh echo '${USER}'` != root ]
+}
+
 [ "USAGE: fastboot_getvar var expected
 
 Returns: true if var output matches expected" ]
@@ -194,6 +208,15 @@
   echo ${O} >&2
 }
 
+[ "USAGE: cleanup
+
+Do nothing: should be redefined when necessary
+
+Returns: cleans up any latent resources, reverses configurations" ]
+cleanup () {
+  :
+}
+
 [ "USAGE: die [-d|-t <epoch>] [message] >/dev/stderr
 
 If -d, or -t <epoch> argument is supplied, dump logcat.
@@ -212,6 +235,7 @@
     shift 2
   fi
   echo "${RED}[  FAILED  ]${NORMAL} ${@}" >&2
+  cleanup
   exit 1
 }
 
@@ -558,6 +582,7 @@
 echo "${GREEN}[       OK ]${NORMAL} /system content remains after reboot" >&2
 # Only root can read vendor if sepolicy permissions are as expected
 if ${enforcing}; then
+  adb_unroot
   B="`adb_cat /vendor/hello`" &&
     die "re-read /vendor/hello after reboot w/o root"
   check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
diff --git a/init/Android.bp b/init/Android.bp
index 3369fb9..9f5d17d 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -19,7 +19,6 @@
     cpp_std: "experimental",
     sanitize: {
         misc_undefined: ["signed-integer-overflow"],
-        address: false,  // TODO(b/120561310): Fix ASAN to work without /proc mounted and re-enable.
     },
     cflags: [
         "-DLOG_UEVENTS=0",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index e1a86e4..169edbe 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1098,86 +1098,6 @@
     }
 }
 
-static Result<Success> bind_mount_file(const char* source, const char* mount_point,
-                                       bool remount_private) {
-    if (remount_private && mount(nullptr, mount_point, nullptr, MS_PRIVATE, nullptr) == -1) {
-        return ErrnoError() << "Could not change " << mount_point << " to a private mount point";
-    }
-    if (mount(source, mount_point, nullptr, MS_BIND, nullptr) == -1) {
-        return ErrnoError() << "Could not bind-mount " << source << " to " << mount_point;
-    }
-    return Success();
-}
-
-static Result<Success> bind_mount_bionic(const char* linker_source, const char* lib_dir_source,
-                                         const char* linker_mount_point, const char* lib_mount_dir,
-                                         bool remount_private) {
-    if (access(linker_source, F_OK) != 0) {
-        return Success();
-    }
-    if (auto result = bind_mount_file(linker_source, linker_mount_point, remount_private);
-        !result) {
-        return result;
-    }
-    for (auto libname : kBionicLibFileNames) {
-        std::string mount_point = lib_mount_dir + libname;
-        std::string source = lib_dir_source + libname;
-        if (auto result = bind_mount_file(source.c_str(), mount_point.c_str(), remount_private);
-            !result) {
-            return result;
-        }
-    }
-    return Success();
-}
-
-// The bootstrap bionic libs and the bootstrap linker are bind-mounted to
-// the mount points for pre-apexd processes.
-static Result<Success> do_prepare_bootstrap_bionic(const BuiltinArguments& args) {
-    static bool prepare_bootstrap_bionic_done = false;
-    if (prepare_bootstrap_bionic_done) {
-        return Error() << "prepare_bootstrap_bionic was already executed. Cannot be executed again";
-    }
-    if (auto result = bind_mount_bionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir,
-                                        kLinkerMountPoint, kBionicLibsMountPointDir, false);
-        !result) {
-        return result;
-    }
-    if (auto result = bind_mount_bionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64,
-                                        kLinkerMountPoint64, kBionicLibsMountPointDir64, false);
-        !result) {
-        return result;
-    }
-
-    LOG(INFO) << "prepare_bootstrap_bionic done";
-    prepare_bootstrap_bionic_done = true;
-    return Success();
-}
-
-// The bionic libs and the dynamic linker from the runtime APEX are bind-mounted
-// to the mount points. As a result, the previous mounts done by
-// prepare_bootstrap_bionic become hidden.
-static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
-    static bool setup_runtime_bionic_done = false;
-    if (setup_runtime_bionic_done) {
-        return Error() << "setup_runtime_bionic was already executed. Cannot be executed again";
-    }
-    if (auto result = bind_mount_bionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir,
-                                        kLinkerMountPoint, kBionicLibsMountPointDir, true);
-        !result) {
-        return result;
-    }
-    if (auto result = bind_mount_bionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64,
-                                        kLinkerMountPoint64, kBionicLibsMountPointDir64, true);
-        !result) {
-        return result;
-    }
-
-    ServiceList::GetInstance().MarkRuntimeAvailable();
-    LOG(INFO) << "setup_runtime_bionic done";
-    setup_runtime_bionic_done = true;
-    return Success();
-}
-
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1216,7 +1136,6 @@
         {"mount_all",               {1,     kMax, {false,  do_mount_all}}},
         {"mount",                   {3,     kMax, {false,  do_mount}}},
         {"parse_apex_configs",      {0,     0,    {false,  do_parse_apex_configs}}},
-        {"prepare_bootstrap_bionic",{0,     0,    {false,  do_prepare_bootstrap_bionic}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
@@ -1225,7 +1144,6 @@
         {"rm",                      {1,     1,    {true,   do_rm}}},
         {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
         {"setprop",                 {2,     2,    {true,   do_setprop}}},
-        {"setup_runtime_bionic",    {0,     0,    {false,  do_setup_runtime_bionic}}},
         {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
         {"start",                   {1,     1,    {false,  do_start}}},
         {"stop",                    {1,     1,    {false,  do_stop}}},
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 008a868..0aa7810 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -20,9 +20,11 @@
 #include <fcntl.h>
 #include <linux/fs.h>
 #include <mntent.h>
+#include <linux/loop.h>
 #include <sys/cdefs.h>
 #include <sys/ioctl.h>
 #include <sys/mount.h>
+#include <sys/swap.h>
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/types.h>
@@ -58,6 +60,7 @@
 using android::base::Split;
 using android::base::StringPrintf;
 using android::base::Timer;
+using android::base::unique_fd;
 
 namespace android {
 namespace init {
@@ -193,7 +196,7 @@
     return true;
 }
 
-static void DumpUmountDebuggingInfo(bool dump_all) {
+static void DumpUmountDebuggingInfo() {
     int status;
     if (!security_getenforce()) {
         LOG(INFO) << "Run lsof";
@@ -202,10 +205,9 @@
                                 true, nullptr, nullptr, 0);
     }
     FindPartitionsToUmount(nullptr, nullptr, true);
-    if (dump_all) {
-        // dump current tasks, this log can be lengthy, so only dump with dump_all
-        android::base::WriteStringToFile("t", "/proc/sysrq-trigger");
-    }
+    // dump current CPU stack traces and uninterruptible tasks
+    android::base::WriteStringToFile("l", "/proc/sysrq-trigger");
+    android::base::WriteStringToFile("w", "/proc/sysrq-trigger");
 }
 
 static UmountStat UmountPartitions(std::chrono::milliseconds timeout) {
@@ -268,11 +270,11 @@
     UmountStat stat = UmountPartitions(timeout - t.duration());
     if (stat != UMOUNT_STAT_SUCCESS) {
         LOG(INFO) << "umount timeout, last resort, kill all and try";
-        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(true);
+        if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
         KillAllProcesses();
         // even if it succeeds, still it is timeout and do not run fsck with all processes killed
         UmountStat st = UmountPartitions(0ms);
-        if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(false);
+        if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo();
     }
 
     if (stat == UMOUNT_STAT_SUCCESS && runFsck) {
@@ -285,6 +287,48 @@
     return stat;
 }
 
+// zram is able to use backing device on top of a loopback device.
+// In order to unmount /data successfully, we have to kill the loopback device first
+#define ZRAM_DEVICE   "/dev/block/zram0"
+#define ZRAM_RESET    "/sys/block/zram0/reset"
+#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
+static void KillZramBackingDevice() {
+    std::string backing_dev;
+    if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
+
+    if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
+
+    // cut the last "\n"
+    backing_dev.erase(backing_dev.length() - 1);
+
+    // shutdown zram handle
+    Timer swap_timer;
+    LOG(INFO) << "swapoff() start...";
+    if (swapoff(ZRAM_DEVICE) == -1) {
+        LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
+        return;
+    }
+    LOG(INFO) << "swapoff() took " << swap_timer;;
+
+    if (!android::base::WriteStringToFile("1", ZRAM_RESET)) {
+        LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
+        return;
+    }
+
+    // clear loopback device
+    unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
+    if (loop.get() < 0) {
+        LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
+        return;
+    }
+
+    if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
+        LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
+        return;
+    }
+    LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
+}
+
 //* Reboot / shutdown the system.
 // cmd ANDROID_RB_* as defined in android_reboot.h
 // reason Reason string like "reboot", "shutdown,userrequested"
@@ -427,6 +471,9 @@
         sync();
         LOG(INFO) << "sync() before umount took" << sync_timer;
     }
+    // 5. drop caches and disable zram backing device, if exist
+    KillZramBackingDevice();
+
     UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
     // Follow what linux shutdown is doing: one more sync with little bit delay
     {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index e4da52c..c0fc3ce 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -434,12 +434,6 @@
 
     selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
     selinux_android_restorecon("/dev/device-mapper", 0);
-
-    selinux_android_restorecon("/sbin/mke2fs_static", 0);
-    selinux_android_restorecon("/sbin/e2fsdroid_static", 0);
-
-    selinux_android_restorecon("/sbin/mkfs.f2fs", 0);
-    selinux_android_restorecon("/sbin/sload.f2fs", 0);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/service.cpp b/init/service.cpp
index f3eafe4..272809f 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -140,43 +140,6 @@
     return Success();
 }
 
-Result<Success> Service::SetUpPreApexdMounts() const {
-    // If a pre-apexd service is 're' launched after the runtime APEX is
-    // available, unmount the linker and bionic libs which are currently
-    // bind mounted to the files in the runtime APEX. This will reveal
-    // the hidden mount points (targetting the bootstrap ones in the
-    // system partition) which were setup before the runtime APEX was
-    // started. Note that these unmounts are done in a separate mount namespace
-    // for the process. It does not affect other processes including the init.
-    if (pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) {
-        if (access(kLinkerMountPoint, F_OK) == 0) {
-            if (umount(kLinkerMountPoint) == -1) {
-                return ErrnoError() << "Could not umount " << kLinkerMountPoint;
-            }
-            for (const auto& libname : kBionicLibFileNames) {
-                std::string mount_point = kBionicLibsMountPointDir + libname;
-                if (umount(mount_point.c_str()) == -1) {
-                    return ErrnoError() << "Could not umount " << mount_point;
-                }
-            }
-        }
-
-        if (access(kLinkerMountPoint64, F_OK) == 0) {
-            if (umount(kLinkerMountPoint64) == -1) {
-                return ErrnoError() << "Could not umount " << kLinkerMountPoint64;
-            }
-            for (const auto& libname : kBionicLibFileNames) {
-                std::string mount_point = kBionicLibsMountPointDir64 + libname;
-                std::string source = kBootstrapBionicLibsDir64 + libname;
-                if (umount(mount_point.c_str()) == -1) {
-                    return ErrnoError() << "Could not umount " << mount_point;
-                }
-            }
-        }
-    }
-    return Success();
-}
-
 Result<Success> Service::SetUpPidNamespace() const {
     if (prctl(PR_SET_NAME, name_.c_str()) == -1) {
         return ErrnoError() << "Could not set name";
@@ -406,7 +369,7 @@
 
     // If we crash > 4 times in 4 minutes, reboot into bootloader or set crashing property
     boot_clock::time_point now = boot_clock::now();
-    if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) {
+    if (((flags_ & SVC_CRITICAL) || classnames_.count("updatable")) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
             if (++crash_count_ > 4) {
                 if (flags_ & SVC_CRITICAL) {
@@ -966,14 +929,6 @@
         scon = *result;
     }
 
-    if (!ServiceList::GetInstance().IsRuntimeAvailable() && !pre_apexd_) {
-        // If this service is started before the runtime APEX gets available,
-        // mark it as pre-apexd one. Note that this marking is permanent. So
-        // for example, if the service is re-launched (e.g., due to crash),
-        // it is still recognized as pre-apexd... for consistency.
-        pre_apexd_ = true;
-    }
-
     LOG(INFO) << "starting service '" << name_ << "'...";
 
     pid_t pid = -1;
@@ -990,37 +945,6 @@
             LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
         }
 
-        // b/122559956: mount namespace is not cloned for the devices that don't support
-        // the update of bionic libraries via APEX. In that case, because the bionic
-        // libraries in the runtime APEX and the bootstrap bionic libraries are
-        // identical, it doesn't matter which libs are used. This is also to avoid the
-        // bug in sdcardfs which is triggered when we have multiple mount namespaces
-        // across vold and the others. BIONIC_UPDATABLE shall be true only for the
-        // devices where kernel has the fix for the sdcardfs bug (see the commit message
-        // for the fix).
-        static bool bionic_updatable =
-                android::base::GetBoolProperty("ro.apex.bionic_updatable", false);
-
-        if (bionic_updatable && pre_apexd_) {
-            // pre-apexd process gets a private copy of the mount namespace.
-            // However, this does not mean that mount/unmount events are not
-            // shared across pre-apexd processes and post-apexd processes.
-            // *Most* of the events are still shared because the propagation
-            // type of / is set to 'shared'. (see `mount rootfs rootfs /shared
-            // rec` in init.rc)
-            //
-            // This unsharing is required to not propagate the mount events
-            // under /system/lib/{libc|libdl|libm}.so and /system/bin/linker(64)
-            // whose propagation type is set to private. With this,
-            // bind-mounting the bionic libs and the dynamic linker from the
-            // runtime APEX to the mount points does not affect pre-apexd
-            // processes which should use the bootstrap ones.
-            if (unshare(CLONE_NEWNS) != 0) {
-                LOG(FATAL) << "Creating a new mount namespace for service"
-                           << " '" << name_ << "' failed: " << strerror(errno);
-            }
-        }
-
         if (namespace_flags_ & CLONE_NEWNS) {
             if (auto result = SetUpMountNamespace(); !result) {
                 LOG(FATAL) << "Service '" << name_
@@ -1028,14 +952,6 @@
             }
         }
 
-        // b/122559956: same as above
-        if (bionic_updatable && pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) {
-            if (auto result = SetUpPreApexdMounts(); !result) {
-                LOG(FATAL) << "Pre-apexd service '" << name_
-                           << "' could not setup the mount points: " << result.error();
-            }
-        }
-
         if (namespace_flags_ & CLONE_NEWPID) {
             // This will fork again to run an init process inside the PID
             // namespace.
@@ -1408,10 +1324,6 @@
     delayed_service_names_.clear();
 }
 
-void ServiceList::MarkRuntimeAvailable() {
-    runtime_available_ = true;
-}
-
 void ServiceList::DelayService(const Service& service) {
     if (services_update_finished_) {
         LOG(ERROR) << "Cannot delay the start of service '" << service.name()
diff --git a/init/service.h b/init/service.h
index 676111f..56e75b0 100644
--- a/init/service.h
+++ b/init/service.h
@@ -62,24 +62,6 @@
 namespace android {
 namespace init {
 
-static constexpr const char* kLinkerMountPoint = "/system/bin/linker";
-static constexpr const char* kBootstrapLinkerPath = "/system/bin/linker";
-static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
-
-static constexpr const char* kBionicLibsMountPointDir = "/system/lib/";
-static constexpr const char* kBootstrapBionicLibsDir = "/system/lib/";
-static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
-
-static constexpr const char* kLinkerMountPoint64 = "/system/bin/linker64";
-static constexpr const char* kBootstrapLinkerPath64 = "/system/bin/linker64";
-static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
-
-static constexpr const char* kBionicLibsMountPointDir64 = "/system/lib64/";
-static constexpr const char* kBootstrapBionicLibsDir64 = "/system/lib64/";
-static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
-
-static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
-
 class Service {
   public:
     Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
@@ -142,7 +124,6 @@
     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_; }
-    bool is_pre_apexd() const { return pre_apexd_; }
 
   private:
     using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -151,7 +132,6 @@
     Result<Success> SetUpMountNamespace() const;
     Result<Success> SetUpPidNamespace() const;
     Result<Success> EnterNamespaces() const;
-    Result<Success> SetUpPreApexdMounts() const;
     void NotifyStateChange(const std::string& new_state) const;
     void StopOrReset(int how);
     void ZapStdio() const;
@@ -262,8 +242,6 @@
     std::vector<std::string> args_;
 
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
-
-    bool pre_apexd_ = false;
 };
 
 class ServiceList {
@@ -306,16 +284,13 @@
     const std::vector<Service*> services_in_shutdown_order() const;
 
     void MarkServicesUpdate();
-    void MarkRuntimeAvailable();
     bool IsServicesUpdated() const { return services_update_finished_; }
-    bool IsRuntimeAvailable() const { return runtime_available_; }
     void DelayService(const Service& service);
 
   private:
     std::vector<std::unique_ptr<Service>> services_;
 
     bool services_update_finished_ = false;
-    bool runtime_available_ = false;
     std::vector<std::string> delayed_service_names_;
 };
 
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 0723612..03edfb5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -190,7 +190,8 @@
  */
 #define AID_OVERFLOWUID 65534 /* unmapped user in the user namespace */
 
-#define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
+/* use the ranges below to determine whether a process is isolated */
+#define AID_ISOLATED_START 90000 /* start of uids for fully isolated sandboxed processes */
 #define AID_ISOLATED_END 99999   /* end of uids for fully isolated sandboxed processes */
 
 #define AID_USER 100000        /* TODO: switch users over to AID_USER_OFFSET */
diff --git a/logcat/Android.bp b/logcat/Android.bp
index b0563a6..0543aba 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -25,9 +25,9 @@
     shared_libs: [
         "libbase",
         "libcutils",
-        "liblog",
         "libpcrecpp",
     ],
+    static_libs: ["liblog"],
     logtags: ["event.logtags"],
 }
 
diff --git a/logcat/tests/Android.bp b/logcat/tests/Android.bp
index e1f4d6f..ab84150 100644
--- a/logcat/tests/Android.bp
+++ b/logcat/tests/Android.bp
@@ -48,10 +48,8 @@
 cc_test {
     name: "logcat-unit-tests",
     defaults: ["logcat-tests-defaults"],
-    shared_libs: [
-        "liblog",
-        "libbase",
-    ],
+    shared_libs: ["libbase"],
+    static_libs: ["liblog"],
     srcs: [
         "logcat_test.cpp",
         "logcatd_test.cpp",
diff --git a/logd/Android.bp b/logd/Android.bp
index 5c79976..3abfc21 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -63,11 +63,13 @@
 
     srcs: ["main.cpp"],
 
-    static_libs: ["liblogd"],
+    static_libs: [
+        "liblog",
+        "liblogd",
+    ],
 
     shared_libs: [
         "libsysutils",
-        "liblog",
         "libcutils",
         "libbase",
         "libpackagelistparser",
diff --git a/logd/tests/Android.bp b/logd/tests/Android.bp
index f15beb2..83a194f 100644
--- a/logd/tests/Android.bp
+++ b/logd/tests/Android.bp
@@ -38,9 +38,9 @@
     shared_libs: [
         "libbase",
         "libcutils",
-        "liblog",
         "libselinux",
     ],
+    static_libs: ["liblog"],
 }
 
 // Build tests for the logger. Run with:
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 9b20964..d1a0ffd 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,12 +12,6 @@
 import /init.${ro.zygote}.rc
 
 on early-init
-    # Mount shared so changes propagate into child namespaces
-    # Do this before other processes are started from init. Otherwise,
-    # processes launched while the propagation type of / is 'private'
-    # won't get mount events from others.
-    mount rootfs rootfs / shared rec
-
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
@@ -46,8 +40,6 @@
     # cgroup for system_server and surfaceflinger
     mkdir /dev/memcg/system 0550 system system
 
-    prepare_bootstrap_bionic
-
     start ueventd
 
 on init
@@ -352,6 +344,8 @@
     # Once everything is setup, no need to modify /.
     # The bind+remount combination allows this to work in containers.
     mount rootfs rootfs / remount bind ro nodev
+    # Mount shared so changes propagate into child namespaces
+    mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
     mount none /mnt/runtime/default /storage bind rec
     mount none none /storage slave rec
@@ -587,14 +581,6 @@
     # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
     exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
 
-    # Wait for apexd to finish activating APEXes before starting more processes.
-    # This certainly reduces the parallelism but is required to make as many processes
-    # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms
-    # so the impact on the booting time is not significant.
-    wait_for_prop apexd.status ready
-    setup_runtime_bionic
-    parse_apex_configs
-
     # If there is no post-fs-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -816,3 +802,6 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
+
+on property:apexd.status=ready
+    parse_apex_configs