Merge "Add UID printing to tombstone headers" into qt-dev
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e417f05..2dd22b3 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -280,6 +280,9 @@
     } else if (type == "sideload") {
         D("setting connection_state to kCsSideload");
         t->SetConnectionState(kCsSideload);
+    } else if (type == "rescue") {
+        D("setting connection_state to kCsRescue");
+        t->SetConnectionState(kCsRescue);
     } else {
         D("setting connection_state to kCsHost");
         t->SetConnectionState(kCsHost);
diff --git a/adb/adb.h b/adb/adb.h
index c60dcbc..3a6f059 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -107,6 +107,7 @@
     kCsHost,
     kCsRecovery,
     kCsSideload,
+    kCsRescue,
 };
 
 inline bool ConnectionStateIsOnline(ConnectionState state) {
@@ -116,6 +117,7 @@
         case kCsHost:
         case kCsRecovery:
         case kCsSideload:
+        case kCsRescue:
             return true;
         default:
             return false;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 43a3e5e..e2a17c5 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -190,7 +190,7 @@
         "scripting:\n"
         " wait-for[-TRANSPORT]-STATE\n"
         "     wait for device to be in the given state\n"
-        "     STATE: device, recovery, sideload, bootloader, or disconnect\n"
+        "     STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n"
         "     TRANSPORT: usb, local, or any [default=any]\n"
         " get-state                print offline | bootloader | device\n"
         " get-serialno             print <serial-number>\n"
@@ -838,26 +838,25 @@
 
 #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
 
-/*
- * The sideload-host protocol serves the data in a file (given on the
- * command line) to the client, using a simple protocol:
- *
- * - The connect message includes the total number of bytes in the
- *   file and a block size chosen by us.
- *
- * - The other side sends the desired block number as eight decimal
- *   digits (eg "00000023" for block 23).  Blocks are numbered from
- *   zero.
- *
- * - We send back the data of the requested block.  The last block is
- *   likely to be partial; when the last block is requested we only
- *   send the part of the block that exists, it's not padded up to the
- *   block size.
- *
- * - When the other side sends "DONEDONE" instead of a block number,
- *   we hang up.
- */
-static int adb_sideload_host(const char* filename) {
+// Connects to the sideload / rescue service on the device (served by minadbd) and sends over the
+// data in an OTA package.
+//
+// It uses a simple protocol as follows.
+//
+// - The connect message includes the total number of bytes in the file and a block size chosen by
+//   us.
+//
+// - The other side sends the desired block number as eight decimal digits (e.g. "00000023" for
+//   block 23). Blocks are numbered from zero.
+//
+// - We send back the data of the requested block. The last block is likely to be partial; when the
+//   last block is requested we only send the part of the block that exists, it's not padded up to
+//   the block size.
+//
+// - When the other side sends "DONEDONE" or "FAILFAIL" instead of a block number, we have done all
+//   the data transfer.
+//
+static int adb_sideload_install(const char* filename, bool rescue_mode) {
     // TODO: use a LinePrinter instead...
     struct stat sb;
     if (stat(filename, &sb) == -1) {
@@ -870,14 +869,18 @@
         return -1;
     }
 
-    std::string service =
-            android::base::StringPrintf("sideload-host:%" PRId64 ":%d",
-                                        static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
+    std::string service = android::base::StringPrintf(
+            "%s:%" PRId64 ":%d", rescue_mode ? "rescue-install" : "sideload-host",
+            static_cast<int64_t>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
     std::string error;
     unique_fd device_fd(adb_connect(service, &error));
     if (device_fd < 0) {
         fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str());
 
+        if (rescue_mode) {
+            return -1;
+        }
+
         // If this is a small enough package, maybe this is an older device that doesn't
         // support sideload-host. Try falling back to the older (<= K) sideload method.
         if (sb.st_size > INT_MAX) {
@@ -901,10 +904,14 @@
         }
         buf[8] = '\0';
 
-        if (strcmp("DONEDONE", buf) == 0) {
+        if (strcmp(kMinadbdServicesExitSuccess, buf) == 0 ||
+            strcmp(kMinadbdServicesExitFailure, buf) == 0) {
             printf("\rTotal xfer: %.2fx%*s\n",
                    static_cast<double>(xfer) / (sb.st_size ? sb.st_size : 1),
                    static_cast<int>(strlen(filename) + 10), "");
+            if (strcmp(kMinadbdServicesExitFailure, buf) == 0) {
+                return 1;
+            }
             return 0;
         }
 
@@ -954,6 +961,33 @@
     }
 }
 
+static int adb_wipe_devices() {
+    auto wipe_devices_message_size = strlen(kMinadbdServicesExitSuccess);
+    std::string error;
+    unique_fd fd(adb_connect(
+            android::base::StringPrintf("rescue-wipe:userdata:%zu", wipe_devices_message_size),
+            &error));
+    if (fd < 0) {
+        fprintf(stderr, "adb: wipe device connection failed: %s\n", error.c_str());
+        return 1;
+    }
+
+    std::string message(wipe_devices_message_size, '\0');
+    if (!ReadFdExactly(fd, message.data(), wipe_devices_message_size)) {
+        fprintf(stderr, "adb: failed to read wipe result: %s\n", strerror(errno));
+        return 1;
+    }
+
+    if (message == kMinadbdServicesExitSuccess) {
+        return 0;
+    }
+
+    if (message != kMinadbdServicesExitFailure) {
+        fprintf(stderr, "adb: got unexpected message from rescue wipe %s\n", message.c_str());
+    }
+    return 1;
+}
+
 /**
  * Run ppp in "notty" mode against a resource listed as the first parameter
  * eg:
@@ -1037,11 +1071,12 @@
     }
 
     if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" &&
-        components[3] != "recovery" && components[3] != "sideload" &&
+        components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" &&
         components[3] != "disconnect") {
         fprintf(stderr,
                 "adb: unknown state %s; "
-                "expected 'any', 'bootloader', 'device', 'recovery', 'sideload', or 'disconnect'\n",
+                "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or "
+                "'disconnect'\n",
                 components[3].c_str());
         return false;
     }
@@ -1627,11 +1662,28 @@
         return adb_kill_server() ? 0 : 1;
     } else if (!strcmp(argv[0], "sideload")) {
         if (argc != 2) error_exit("sideload requires an argument");
-        if (adb_sideload_host(argv[1])) {
+        if (adb_sideload_install(argv[1], false /* rescue_mode */)) {
             return 1;
         } else {
             return 0;
         }
+    } else if (!strcmp(argv[0], "rescue")) {
+        // adb rescue getprop <prop>
+        // adb rescue install <filename>
+        // adb rescue wipe userdata
+        if (argc != 3) error_exit("rescue requires two arguments");
+        if (!strcmp(argv[1], "getprop")) {
+            return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2]));
+        } else if (!strcmp(argv[1], "install")) {
+            if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) {
+                return 1;
+            }
+        } else if (!strcmp(argv[1], "wipe") && !strcmp(argv[2], "userdata")) {
+            return adb_wipe_devices();
+        } else {
+            error_exit("invalid rescue argument");
+        }
+        return 0;
     } else if (!strcmp(argv[0], "tcpip")) {
         if (argc != 2) error_exit("tcpip requires an argument");
         int port;
diff --git a/adb/services.cpp b/adb/services.cpp
index cf346ba..335ffc4 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -227,6 +227,8 @@
             sinfo->state = kCsDevice;
         } else if (name == "-recovery") {
             sinfo->state = kCsRecovery;
+        } else if (name == "-rescue") {
+            sinfo->state = kCsRescue;
         } else if (name == "-sideload") {
             sinfo->state = kCsSideload;
         } else if (name == "-bootloader") {
diff --git a/adb/services.h b/adb/services.h
index 0ce25ba..6fc89d7 100644
--- a/adb/services.h
+++ b/adb/services.h
@@ -23,5 +23,10 @@
 constexpr char kShellServiceArgPty[] = "pty";
 constexpr char kShellServiceArgShellProtocol[] = "v2";
 
+// Special flags sent by minadbd. They indicate the end of sideload transfer and the result of
+// installation or wipe.
+constexpr char kMinadbdServicesExitSuccess[] = "DONEDONE";
+constexpr char kMinadbdServicesExitFailure[] = "FAILFAIL";
+
 unique_fd create_service_thread(const char* service_name, std::function<void(unique_fd)> func);
 #endif  // SERVICES_H_
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 15c3a9a..841865a 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1012,6 +1012,8 @@
             return "host";
         case kCsRecovery:
             return "recovery";
+        case kCsRescue:
+            return "rescue";
         case kCsNoPerm:
             return UsbNoPermissionsShortHelpText();
         case kCsSideload:
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 0cf3378..2e226da 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -183,6 +183,12 @@
             ],
         },
     },
+
+    product_variables: {
+        debuggable: {
+            cflags: ["-DROOT_POSSIBLE"],
+        },
+    },
 }
 
 cc_test {
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index 94fcfb2..c606970 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -74,10 +74,7 @@
     return;
   }
 
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
-  }
+  log_backtrace(&log, unwinder, "  ");
 }
 
 void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 238c00c..f189c45 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -73,9 +73,12 @@
 void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 
 namespace unwindstack {
+class Unwinder;
 class Memory;
 }
 
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
+
 void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&);
 
 void read_with_default(const char* path, char* buf, size_t len, const char* default_value);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 89a5a45..d246722 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -372,13 +372,6 @@
   }
 }
 
-void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
-  unwinder->SetDisplayBuildID(true);
-  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
-    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
-  }
-}
-
 static void print_register_row(log_t* log,
                                const std::vector<std::pair<std::string, uint64_t>>& registers) {
   std::string output;
@@ -471,7 +464,7 @@
     _LOG(log, logtype::THREAD, "Failed to unwind");
   } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
-    dump_backtrace(log, unwinder, "    ");
+    log_backtrace(log, unwinder, "    ");
 
     _LOG(log, logtype::STACK, "\nstack:\n");
     dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 7aebea8..9b2779a 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -38,6 +38,7 @@
 #include <debuggerd/handler.h>
 #include <log/log.h>
 #include <unwindstack/Memory.h>
+#include <unwindstack/Unwinder.h>
 
 using android::base::unique_fd;
 
@@ -422,3 +423,22 @@
   // Then give up...
   return "?";
 }
+
+void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  if (unwinder->elf_from_memory_not_file()) {
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix);
+    _LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix);
+#if defined(ROOT_POSSIBLE)
+    _LOG(log, logtype::BACKTRACE,
+         "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
+#endif
+  }
+
+  unwinder->SetDisplayBuildID(true);
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
+  }
+}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 5114f55..c1aafda 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1695,11 +1695,12 @@
 
 std::string fs_mgr_get_super_partition_name(int slot) {
     // Devices upgrading to dynamic partitions are allowed to specify a super
-    // partition name, assumed to be A/B (non-A/B retrofit is not supported).
-    // For devices launching with dynamic partition support, the partition
-    // name must be "super".
+    // partition name. This includes cuttlefish, which is a non-A/B device.
     std::string super_partition;
     if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) {
+        if (fs_mgr_get_slot_suffix().empty()) {
+            return super_partition;
+        }
         std::string suffix;
         if (slot == 0) {
             suffix = "_a";
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 4043fc6..da049ef 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -38,6 +38,7 @@
 
 using android::base::ParseByteCount;
 using android::base::ParseInt;
+using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::StartsWith;
 
@@ -660,6 +661,8 @@
         TransformFstabForGsi(fstab);
     }
 
+    SkipMountingPartitions(fstab);
+
     return true;
 }
 
@@ -687,6 +690,36 @@
         return false;
     }
 
+    SkipMountingPartitions(fstab);
+
+    return true;
+}
+
+// For GSI to skip mounting /product and /product_services, until there are
+// well-defined interfaces between them and /system. Otherwise, the GSI flashed
+// on /system might not be able to work with /product and /product_services.
+// When they're skipped here, /system/product and /system/product_services in
+// GSI will be used.
+bool SkipMountingPartitions(Fstab* fstab) {
+    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
+
+    std::string skip_config;
+    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
+        return true;
+    }
+
+    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
+        if (skip_mount_point.empty()) {
+            continue;
+        }
+        auto it = std::remove_if(fstab->begin(), fstab->end(),
+                                 [&skip_mount_point](const auto& entry) {
+                                     return entry.mount_point == skip_mount_point;
+                                 });
+        fstab->erase(it, fstab->end());
+        LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+    }
+
     return true;
 }
 
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index dea4844..730d3db 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -715,7 +715,7 @@
     }
 
     if (changed || partition_create) {
-        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+        if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
                                     scratch_device))
             return false;
 
@@ -940,7 +940,7 @@
             auto slot_number = fs_mgr_overlayfs_slot_number();
             auto super_device = fs_mgr_overlayfs_super_device(slot_number);
             const auto partition_name = android::base::Basename(kScratchMountPoint);
-            CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
+            CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s,
                                    &scratch_device);
         }
         mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 88da41d..d7afed6 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -99,6 +99,7 @@
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
 bool ReadFstabFromDt(Fstab* fstab, bool log = true);
 bool ReadDefaultFstab(Fstab* fstab);
+bool SkipMountingPartitions(Fstab* fstab);
 
 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
 
diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
index 6a3e2c0..c192bf5 100644
--- a/fs_mgr/libfs_avb/avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -36,6 +36,7 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <libavb/libavb.h>
+#include <libdm/dm.h>
 #include <utils/Compat.h>
 
 #include "util.h"
@@ -104,6 +105,20 @@
     return AVB_IO_RESULT_OK;
 }
 
+// Converts a partition name (with ab_suffix) to the corresponding mount point.
+// e.g., "system_a" => "/system",
+// e.g., "vendor_a" => "/vendor",
+static std::string DeriveMountPoint(const std::string& partition_name) {
+    const std::string ab_suffix = fs_mgr_get_slot_suffix();
+    std::string mount_point(partition_name);
+    auto found = partition_name.rfind(ab_suffix);
+    if (found != std::string::npos) {
+        mount_point.erase(found);  // converts system_a => system
+    }
+
+    return "/" + mount_point;
+}
+
 FsManagerAvbOps::FsManagerAvbOps() {
     // We only need to provide the implementation of read_from_partition()
     // operation since that's all what is being used by the avb_slot_verify().
@@ -122,14 +137,53 @@
     avb_ops_.user_data = this;
 }
 
+// Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
+// dm-linear path for it. e.g., /dev/block/dm-0. If not found, returns an empty string.
+// This assumes that the prefix of the partition name and the mount point are the same.
+// e.g., partition vendor_a is mounted under /vendor, product_a is mounted under /product, etc.
+// This might not be true for some special fstab files, e.g., fstab.postinstall.
+// But it's good enough for the default fstab. Also note that the logical path is a
+// fallback solution when the physical path (/dev/block/by-name/<partition>) cannot be found.
+std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) {
+    if (fstab_.empty() && !ReadDefaultFstab(&fstab_)) {
+        return "";
+    }
+
+    const auto mount_point = DeriveMountPoint(partition_name);
+    if (mount_point.empty()) return "";
+
+    auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);
+    if (!fstab_entry) return "";
+
+    std::string device_path;
+    if (fstab_entry->fs_mgr_flags.logical) {
+        dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
+        if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) {
+            LERROR << "Failed to resolve logical device path for: " << fstab_entry->blk_device;
+            return "";
+        }
+        return device_path;
+    }
+
+    return "";
+}
+
 AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
                                                size_t num_bytes, void* buffer,
                                                size_t* out_num_read) {
-    const std::string path = "/dev/block/by-name/"s + partition;
+    std::string path = "/dev/block/by-name/"s + partition;
 
     // Ensures the device path (a symlink created by init) is ready to access.
     if (!WaitForFile(path, 1s)) {
-        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+        LERROR << "Device path not found: " << path;
+        // Falls back to logical path if the physical path is not found.
+        // This mostly only works for emulator (no bootloader). Because in normal
+        // device, bootloader is unable to read logical partitions. So if libavb in
+        // the bootloader failed to read a physical partition, it will failed to boot
+        // the HLOS and we won't reach the code here.
+        path = GetLogicalPath(partition);
+        if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
+        LINFO << "Fallback to use logical device path: " << path;
     }
 
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
index a849d94..b39812d 100644
--- a/fs_mgr/libfs_avb/avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -28,6 +28,7 @@
 #include <vector>
 
 #include <fs_avb/types.h>
+#include <fstab/fstab.h>
 #include <libavb/libavb.h>
 
 namespace android {
@@ -60,7 +61,9 @@
                                       std::vector<VBMetaData>* out_vbmeta_images);
 
   private:
+    std::string GetLogicalPath(const std::string& partition_name);
     AvbOps avb_ops_;
+    Fstab fstab_;
 };
 
 }  // namespace fs_mgr
diff --git a/init/Android.bp b/init/Android.bp
index 69ee34f..69498ac 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -61,6 +61,7 @@
     static_libs: [
         "libseccomp_policy",
         "libavb",
+        "libc++fs",
         "libcgrouprc_format",
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
diff --git a/init/Android.mk b/init/Android.mk
index 39af0e6..b02c926 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -65,15 +65,22 @@
 LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)
 LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED)
 
+# Install adb_debug.prop into debug ramdisk.
+# This allows adb root on a user build, when debug ramdisk is used.
+LOCAL_REQUIRED_MODULES := \
+   adb_debug.prop \
+
 # Set up the same mount points on the ramdisk that system-as-root contains.
 LOCAL_POST_INSTALL_CMD := mkdir -p \
     $(TARGET_RAMDISK_OUT)/apex \
+    $(TARGET_RAMDISK_OUT)/debug_ramdisk \
     $(TARGET_RAMDISK_OUT)/dev \
     $(TARGET_RAMDISK_OUT)/mnt \
     $(TARGET_RAMDISK_OUT)/proc \
     $(TARGET_RAMDISK_OUT)/sys \
 
 LOCAL_STATIC_LIBRARIES := \
+    libc++fs \
     libfs_avb \
     libfs_mgr \
     libfec \
diff --git a/init/debug_ramdisk.h b/init/debug_ramdisk.h
new file mode 100644
index 0000000..4e3a395
--- /dev/null
+++ b/init/debug_ramdisk.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace init {
+
+constexpr const char kDebugRamdiskProp[] = "/debug_ramdisk/adb_debug.prop";
+constexpr const char kDebugRamdiskSEPolicy[] = "/debug_ramdisk/userdebug_plat_sepolicy.cil";
+
+}  // namespace init
+}  // namespace android
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index c566676..8b95e38 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <filesystem>
 #include <string>
 #include <vector>
 
@@ -35,6 +36,7 @@
 #include <cutils/android_reboot.h>
 #include <private/android_filesystem_config.h>
 
+#include "debug_ramdisk.h"
 #include "first_stage_mount.h"
 #include "reboot_utils.h"
 #include "switch_root.h"
@@ -44,6 +46,8 @@
 
 using namespace std::literals;
 
+namespace fs = std::filesystem;
+
 namespace android {
 namespace init {
 
@@ -159,6 +163,9 @@
     CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                     "mode=0755,uid=0,gid=0"));
 
+    // /debug_ramdisk is used to preserve additional files from the debug ramdisk
+    CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                    "mode=0755,uid=0,gid=0"));
 #undef CHECKCALL
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
@@ -202,7 +209,14 @@
     // If this file is present, the second-stage init will use a userdebug sepolicy
     // and load adb_debug.prop to allow adb root, if the device is unlocked.
     if (access("/force_debuggable", F_OK) == 0) {
-        setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+        std::error_code ec;  // to invoke the overloaded copy_file() that won't throw.
+        if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
+            !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
+            LOG(ERROR) << "Failed to setup debug ramdisk";
+        } else {
+            // setenv for second-stage init to read above kDebugRamdisk* files.
+            setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+        }
     }
 
     if (!DoFirstStageMount()) {
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 3900f72..3e76556 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -43,7 +43,6 @@
 #include "uevent_listener.h"
 #include "util.h"
 
-using android::base::ReadFileToString;
 using android::base::Split;
 using android::base::Timer;
 using android::fs_mgr::AvbHandle;
@@ -55,6 +54,7 @@
 using android::fs_mgr::FstabEntry;
 using android::fs_mgr::ReadDefaultFstab;
 using android::fs_mgr::ReadFstabFromDt;
+using android::fs_mgr::SkipMountingPartitions;
 
 using namespace std::literals;
 
@@ -524,38 +524,10 @@
     return true;
 }
 
-// For GSI to skip mounting /product and /product_services, until there are
-// well-defined interfaces between them and /system. Otherwise, the GSI flashed
-// on /system might not be able to work with /product and /product_services.
-// When they're skipped here, /system/product and /system/product_services in
-// GSI will be used.
-bool FirstStageMount::TrySkipMountingPartitions() {
-    constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
-
-    std::string skip_config;
-    if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
-        return true;
-    }
-
-    for (const auto& skip_mount_point : Split(skip_config, "\n")) {
-        if (skip_mount_point.empty()) {
-            continue;
-        }
-        auto it = std::remove_if(fstab_.begin(), fstab_.end(),
-                                 [&skip_mount_point](const auto& entry) {
-                                     return entry.mount_point == skip_mount_point;
-                                 });
-        fstab_.erase(it, fstab_.end());
-        LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
-    }
-
-    return true;
-}
-
 bool FirstStageMount::MountPartitions() {
     if (!TrySwitchSystemAsRoot()) return false;
 
-    if (!TrySkipMountingPartitions()) return false;
+    if (!SkipMountingPartitions(&fstab_)) return false;
 
     for (auto current = fstab_.begin(); current != fstab_.end();) {
         // We've already mounted /system above.
diff --git a/init/init.cpp b/init/init.cpp
index 0f44efd..c79e459 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -621,6 +621,12 @@
     });
 }
 
+static void UmountDebugRamdisk() {
+    if (umount("/debug_ramdisk") != 0) {
+        LOG(ERROR) << "Failed to umount /debug_ramdisk";
+    }
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -630,6 +636,11 @@
     InitKernelLogging(argv, InitAborter);
     LOG(INFO) << "init second stage started!";
 
+    // Set init and its forked children's oom_adj.
+    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
+        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
+    }
+
     // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
     GlobalSeccomp();
 
@@ -685,6 +696,7 @@
     InstallSignalFdHandler(&epoll);
 
     property_load_boot_defaults(load_debug_prop);
+    UmountDebugRamdisk();
     fs_mgr_vendor_overlay_mount_all();
     export_oem_lock_status();
     StartPropertyService(&epoll);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index fc5538c..bca73c9 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -56,6 +56,7 @@
 #include <selinux/label.h>
 #include <selinux/selinux.h>
 
+#include "debug_ramdisk.h"
 #include "epoll.h"
 #include "init.h"
 #include "persistent_properties.h"
@@ -889,9 +890,8 @@
     load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
 
     if (load_debug_prop) {
-        constexpr static const char kAdbDebugProp[] = "/system/etc/adb_debug.prop";
-        LOG(INFO) << "Loading " << kAdbDebugProp;
-        load_properties_from_file(kAdbDebugProp, nullptr, &properties);
+        LOG(INFO) << "Loading " << kDebugRamdiskProp;
+        load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
     }
 
     for (const auto& [name, value] : properties) {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index aa66baa..132fc13 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -64,6 +64,7 @@
 #include <fs_avb/fs_avb.h>
 #include <selinux/android.h>
 
+#include "debug_ramdisk.h"
 #include "reboot_utils.h"
 #include "util.h"
 
@@ -271,8 +272,6 @@
 }
 
 constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil";
-constexpr const char userdebug_plat_policy_cil_file[] =
-        "/system/etc/selinux/userdebug_plat_sepolicy.cil";
 
 bool IsSplitPolicyDevice() {
     return access(plat_policy_cil_file, R_OK) != -1;
@@ -292,7 +291,7 @@
     const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
     bool use_userdebug_policy =
             ((force_debuggable_env && "true"s == force_debuggable_env) &&
-             AvbHandle::IsDeviceUnlocked() && access(userdebug_plat_policy_cil_file, F_OK) == 0);
+             AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0);
     if (use_userdebug_policy) {
         LOG(WARNING) << "Using userdebug system sepolicy";
     }
@@ -367,7 +366,7 @@
     // clang-format off
     std::vector<const char*> compile_args {
         "/system/bin/secilc",
-        use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file,
+        use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,
         "-m", "-M", "true", "-G", "-N",
         "-c", version_as_string.c_str(),
         plat_mapping_file.c_str(),
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 5cc0857..e460b1a 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -220,7 +220,9 @@
       }
     }
 
-    if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) {
+    // Initialize the anonymous namespace with the first non-empty library path.
+    if (!library_path.empty() && !initialized_ &&
+        !InitPublicNamespace(library_path.c_str(), error_msg)) {
       return nullptr;
     }
 
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 86e6035..7e6bf45 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -24,16 +24,20 @@
 __BEGIN_DECLS
 
 static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2";
-static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
 
 bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path);
 bool CgroupGetAttributePath(const std::string& attr_name, std::string* path);
 bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
 
-bool UsePerAppMemcg();
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+                        bool use_fd_cache = false);
 
-bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles);
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+#ifndef __ANDROID_VNDK__
+
+static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
+
+bool UsePerAppMemcg();
 
 // Return 0 and removes the cgroup if there are no longer any processes in it.
 // Returns -1 in the case of an error occurring or if there are processes still running
@@ -54,4 +58,6 @@
 
 void removeAllProcessGroups(void);
 
+#endif // __ANDROID_VNDK__
+
 __END_DECLS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index abe63dd..1485ae9 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -112,12 +112,16 @@
     return memcg_supported;
 }
 
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+                        bool use_fd_cache) {
     const TaskProfiles& tp = TaskProfiles::GetInstance();
 
     for (const auto& name : profiles) {
-        const TaskProfile* profile = tp.GetProfile(name);
+        TaskProfile* profile = tp.GetProfile(name);
         if (profile != nullptr) {
+            if (use_fd_cache) {
+                profile->EnableResourceCaching();
+            }
             if (!profile->ExecuteForProcess(uid, pid)) {
                 PLOG(WARNING) << "Failed to apply " << name << " process profile";
             }
@@ -129,12 +133,15 @@
     return true;
 }
 
-bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles) {
+bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
     const TaskProfiles& tp = TaskProfiles::GetInstance();
 
     for (const auto& name : profiles) {
-        const TaskProfile* profile = tp.GetProfile(name);
+        TaskProfile* profile = tp.GetProfile(name);
         if (profile != nullptr) {
+            if (use_fd_cache) {
+                profile->EnableResourceCaching();
+            }
             if (!profile->ExecuteForTask(tid)) {
                 PLOG(WARNING) << "Failed to apply " << name << " task profile";
             }
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index ab0f1ca..fe4f93b 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -46,26 +46,34 @@
 
     switch (policy) {
         case SP_BACKGROUND:
-            return SetTaskProfiles(tid, {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
-                                         "TimerSlackHigh"})
+            return SetTaskProfiles(tid,
+                                   {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority",
+                                    "TimerSlackHigh"},
+                                   true)
                            ? 0
                            : -1;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
-            return SetTaskProfiles(tid, {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
-                                         "TimerSlackNormal"})
+            return SetTaskProfiles(tid,
+                                   {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority",
+                                    "TimerSlackNormal"},
+                                   true)
                            ? 0
                            : -1;
         case SP_TOP_APP:
-            return SetTaskProfiles(tid, {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
-                                         "TimerSlackNormal"})
+            return SetTaskProfiles(tid,
+                                   {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority",
+                                    "TimerSlackNormal"},
+                                   true)
                            ? 0
                            : -1;
         case SP_SYSTEM:
-            return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}, true) ? 0 : -1;
         case SP_RESTRICTED:
-            return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}, true)
+                           ? 0
+                           : -1;
         default:
             break;
     }
@@ -126,17 +134,17 @@
 
     switch (policy) {
         case SP_BACKGROUND:
-            return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}, true) ? 0 : -1;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
-            return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
         case SP_TOP_APP:
-            return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}, true) ? 0 : -1;
         case SP_RT_APP:
-            return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}, true) ? 0 : -1;
         default:
-            return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1;
+            return SetTaskProfiles(tid, {"TimerSlackNormal"}, true) ? 0 : -1;
     }
 
     return 0;
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4b45c87..40d8d90 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -138,31 +138,38 @@
 
 SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
     : controller_(c), path_(p) {
-#ifdef CACHE_FILE_DESCRIPTORS
-    // cache file descriptor only if path is app independent
+    // file descriptors for app-dependent paths can't be cached
     if (IsAppDependentPath(path_)) {
         // file descriptor is not cached
-        fd_.reset(-2);
+        fd_.reset(FDS_APP_DEPENDENT);
         return;
     }
 
-    std::string tasks_path = c.GetTasksFilePath(p);
+    // file descriptor can be cached later on request
+    fd_.reset(FDS_NOT_CACHED);
+}
+
+void SetCgroupAction::EnableResourceCaching() {
+    if (fd_ != FDS_NOT_CACHED) {
+        return;
+    }
+
+    std::string tasks_path = controller_.GetTasksFilePath(path_);
 
     if (access(tasks_path.c_str(), W_OK) != 0) {
         // file is not accessible
-        fd_.reset(-1);
+        fd_.reset(FDS_INACCESSIBLE);
         return;
     }
 
     unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
     if (fd < 0) {
         PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
-        fd_.reset(-1);
+        fd_.reset(FDS_INACCESSIBLE);
         return;
     }
 
     fd_ = std::move(fd);
-#endif
 }
 
 bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
@@ -184,8 +191,7 @@
 }
 
 bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
-#ifdef CACHE_FILE_DESCRIPTORS
-    if (fd_ >= 0) {
+    if (IsFdValid()) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(pid, fd_)) {
             LOG(ERROR) << "Failed to add task into cgroup";
@@ -194,12 +200,12 @@
         return true;
     }
 
-    if (fd_ == -1) {
+    if (fd_ == FDS_INACCESSIBLE) {
         // no permissions to access the file, ignore
         return true;
     }
 
-    // this is app-dependent path, file descriptor is not cached
+    // this is app-dependent path and fd is not cached or cached fd can't be used
     std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
     unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
     if (tmp_fd < 0) {
@@ -212,25 +218,10 @@
     }
 
     return true;
-#else
-    std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
-    unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
-    if (tmp_fd < 0) {
-        // no permissions to access the file, ignore
-        return true;
-    }
-    if (!AddTidToCgroup(pid, tmp_fd)) {
-        LOG(ERROR) << "Failed to add task into cgroup";
-        return false;
-    }
-
-    return true;
-#endif
 }
 
 bool SetCgroupAction::ExecuteForTask(int tid) const {
-#ifdef CACHE_FILE_DESCRIPTORS
-    if (fd_ >= 0) {
+    if (IsFdValid()) {
         // fd is cached, reuse it
         if (!AddTidToCgroup(tid, fd_)) {
             LOG(ERROR) << "Failed to add task into cgroup";
@@ -239,20 +230,23 @@
         return true;
     }
 
-    if (fd_ == -1) {
+    if (fd_ == FDS_INACCESSIBLE) {
         // no permissions to access the file, ignore
         return true;
     }
 
-    // application-dependent path can't be used with tid
-    LOG(ERROR) << "Application profile can't be applied to a thread";
-    return false;
-#else
+    if (fd_ == FDS_APP_DEPENDENT) {
+        // application-dependent path can't be used with tid
+        PLOG(ERROR) << "Application profile can't be applied to a thread";
+        return false;
+    }
+
+    // fd was not cached because cached fd can't be used
     std::string tasks_path = controller()->GetTasksFilePath(path_);
     unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
     if (tmp_fd < 0) {
-        // no permissions to access the file, ignore
-        return true;
+        PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
+        return false;
     }
     if (!AddTidToCgroup(tid, tmp_fd)) {
         LOG(ERROR) << "Failed to add task into cgroup";
@@ -260,7 +254,6 @@
     }
 
     return true;
-#endif
 }
 
 bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const {
@@ -284,6 +277,18 @@
     return true;
 }
 
+void TaskProfile::EnableResourceCaching() {
+    if (res_cached_) {
+        return;
+    }
+
+    for (auto& element : elements_) {
+        element->EnableResourceCaching();
+    }
+
+    res_cached_ = true;
+}
+
 TaskProfiles& TaskProfiles::GetInstance() {
     // Deliberately leak this object to avoid a race between destruction on
     // process exit and concurrent access from another thread.
@@ -411,7 +416,7 @@
     return true;
 }
 
-const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
+TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
     auto iter = profiles_.find(name);
 
     if (iter != profiles_.end()) {
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 37cc305..445647d 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -48,6 +48,8 @@
     // Default implementations will fail
     virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
     virtual bool ExecuteForTask(int) const { return false; };
+
+    virtual void EnableResourceCaching() {}
 };
 
 // Profile actions
@@ -110,31 +112,40 @@
 
     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
     virtual bool ExecuteForTask(int tid) const;
+    virtual void EnableResourceCaching();
 
     const CgroupController* controller() const { return &controller_; }
     std::string path() const { return path_; }
 
   private:
+    enum FdState {
+        FDS_INACCESSIBLE = -1,
+        FDS_APP_DEPENDENT = -2,
+        FDS_NOT_CACHED = -3,
+    };
+
     CgroupController controller_;
     std::string path_;
-#ifdef CACHE_FILE_DESCRIPTORS
     android::base::unique_fd fd_;
-#endif
 
     static bool IsAppDependentPath(const std::string& path);
     static bool AddTidToCgroup(int tid, int fd);
+
+    bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
 };
 
 class TaskProfile {
   public:
-    TaskProfile() {}
+    TaskProfile() : res_cached_(false) {}
 
     void Add(std::unique_ptr<ProfileAction> e) { elements_.push_back(std::move(e)); }
 
     bool ExecuteForProcess(uid_t uid, pid_t pid) const;
     bool ExecuteForTask(int tid) const;
+    void EnableResourceCaching();
 
   private:
+    bool res_cached_;
     std::vector<std::unique_ptr<ProfileAction>> elements_;
 };
 
@@ -143,7 +154,7 @@
     // Should be used by all users
     static TaskProfiles& GetInstance();
 
-    const TaskProfile* GetProfile(const std::string& name) const;
+    TaskProfile* GetProfile(const std::string& name) const;
     const ProfileAttribute* GetAttribute(const std::string& name) const;
 
   private:
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 28373b2..03658b4 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -161,6 +161,7 @@
   // option is used.
   std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
   if (Elf::IsValidElf(memory.get())) {
+    memory_backed_elf = true;
     return memory.release();
   }
 
@@ -184,6 +185,7 @@
       new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0));
   ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
 
+  memory_backed_elf = true;
   return ranges;
 }
 
@@ -237,6 +239,7 @@
     std::lock_guard<std::mutex> guard(prev_map->mutex_);
     if (prev_map->elf.get() == nullptr) {
       prev_map->elf = elf;
+      prev_map->memory_backed_elf = memory_backed_elf;
     }
   }
   return elf.get();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index f3d2b5e..26626b5 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -141,6 +141,7 @@
   frames_.clear();
   last_error_.code = ERROR_NONE;
   last_error_.address = 0;
+  elf_from_memory_not_file_ = false;
 
   ArchEnum arch = regs_->Arch();
 
@@ -164,6 +165,12 @@
         break;
       }
       elf = map_info->GetElf(process_memory_, arch);
+      // If this elf is memory backed, and there is a valid file, then set
+      // an indicator that we couldn't open the file.
+      if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
+          map_info->name[0] != '[') {
+        elf_from_memory_not_file_ = true;
+      }
       step_pc = regs_->pc();
       rel_pc = elf->GetRelPc(step_pc, map_info);
       // Everyone except elf data in gdb jit debug maps uses the relative pc.
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index e938986..025fd98 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -75,6 +75,9 @@
   // make it easier to move to a fine grained lock in the future.
   std::atomic_uintptr_t build_id;
 
+  // Set to true if the elf file data is coming from memory.
+  bool memory_backed_elf = false;
+
   // This function guarantees it will never return nullptr.
   Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
 
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 75be209..52b3578 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -111,6 +111,8 @@
   void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
 #endif
 
+  bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
+
   ErrorCode LastErrorCode() { return last_error_.code; }
   uint64_t LastErrorAddress() { return last_error_.address; }
 
@@ -132,6 +134,9 @@
   bool resolve_names_ = true;
   bool embedded_soname_ = true;
   bool display_build_id_ = false;
+  // True if at least one elf file is coming from memory and not the related
+  // file. This is only true if there is an actual file backing up the elf.
+  bool elf_from_memory_not_file_ = false;
   ErrorData last_error_;
 };
 
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 2ddadef..6be8bdc 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -108,6 +108,7 @@
   info.end = 0x101;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
 }
 
 // Verify that if the offset is non-zero but there is no elf at the offset,
@@ -117,6 +118,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
@@ -140,32 +142,40 @@
   // offset to zero.
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.offset = 0;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.flags = PROT_READ;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0x100U, info.elf_start_offset);
 
   prev_info.name = info.name;
   info.elf_offset = 0;
   info.elf_start_offset = 0;
+  info.memory_backed_elf = false;
   memory.reset(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0x100U, info.elf_offset);
   EXPECT_EQ(0U, info.elf_start_offset);
 }
@@ -177,6 +187,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -201,6 +212,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x1000U, info.elf_start_offset);
 
@@ -218,6 +230,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(info.memory_backed_elf);
   ASSERT_EQ(0U, info.elf_offset);
   EXPECT_EQ(0x2000U, info.elf_start_offset);
 
@@ -259,6 +272,7 @@
 
   std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_TRUE(info.memory_backed_elf);
 
   memset(buffer.data(), 0, buffer.size());
   ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
@@ -290,6 +304,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x4000UL, map_info->elf_offset);
   EXPECT_EQ(0x4000UL, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_start_offset);
@@ -336,6 +351,7 @@
 
   std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(mem.get() != nullptr);
+  EXPECT_TRUE(map_info->memory_backed_elf);
   EXPECT_EQ(0x1000UL, map_info->elf_offset);
   EXPECT_EQ(0xb000UL, map_info->offset);
   EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
@@ -374,6 +390,7 @@
   // extend over the executable segment.
   std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
   ASSERT_TRUE(memory.get() != nullptr);
+  EXPECT_FALSE(map_info->memory_backed_elf);
   std::vector<uint8_t> buffer(0x100);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0U, map_info->elf_offset);
@@ -388,7 +405,9 @@
   ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
   ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
 
+  map_info->memory_backed_elf = false;
   memory.reset(map_info->CreateMemory(process_memory_));
+  EXPECT_FALSE(map_info->memory_backed_elf);
   EXPECT_EQ(0x2000U, map_info->offset);
   EXPECT_EQ(0x1000U, map_info->elf_offset);
   EXPECT_EQ(0x1000U, map_info->elf_start_offset);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 48e038e..f635021 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -108,6 +108,24 @@
     const auto& info2 = *--maps_->end();
     info2->elf_offset = 0x8000;
 
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
+    const auto& info3 = *--maps_->end();
+    info3->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
+    const auto& info4 = *--maps_->end();
+    info4->memory_backed_elf = true;
+
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
+    const auto& info5 = *--maps_->end();
+    info5->memory_backed_elf = true;
+
     process_memory_.reset(new MemoryFake);
   }
 
@@ -140,6 +158,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -204,6 +223,7 @@
   unwinder.SetResolveNames(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -263,6 +283,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -292,6 +313,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -321,6 +343,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -351,6 +374,7 @@
   unwinder.SetEmbeddedSoname(false);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -387,6 +411,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -419,6 +444,7 @@
   Unwinder unwinder(20, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(20U, unwinder.NumFrames());
 
@@ -461,6 +487,7 @@
   std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
   unwinder.Unwind(&skip_libs);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -522,6 +549,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -569,6 +597,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -588,6 +617,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 }
@@ -602,6 +632,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -638,6 +669,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -703,6 +735,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -752,6 +785,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -799,6 +833,7 @@
   std::vector<std::string> skip_names{"libanother.so"};
   unwinder.Unwind(&skip_names);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(0U, unwinder.NumFrames());
 }
@@ -821,6 +856,7 @@
   std::vector<std::string> suffixes{"oat"};
   unwinder.Unwind(nullptr, &suffixes);
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
   // Make sure the elf was not initialized.
@@ -879,6 +915,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -937,6 +974,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -980,6 +1018,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(2U, unwinder.NumFrames());
 
@@ -1026,6 +1065,7 @@
   Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(3U, unwinder.NumFrames());
 
@@ -1084,6 +1124,7 @@
   Unwinder unwinder(1, maps_.get(), &regs_, process_memory_);
   unwinder.Unwind();
   EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
 
   ASSERT_EQ(1U, unwinder.NumFrames());
 
@@ -1103,6 +1144,96 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, elf_from_memory_not_file) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc0050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_TRUE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc0050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/fake/unreadable.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc0000U, frame->map_start);
+  EXPECT_EQ(0xc1000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc1050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc1050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("[vdso]", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc1000U, frame->map_start);
+  EXPECT_EQ(0xc2000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
+TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc2050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc2050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc2000U, frame->map_start);
+  EXPECT_EQ(0xc3000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
   RegsFake regs_arm(10);
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5d307b8..7ff1588 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -97,7 +97,7 @@
 #
 # create some directories (some are mount points) and symlinks
 LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
-    sbin dev proc sys system data odm oem acct config storage mnt apex $(BOARD_ROOT_EXTRA_FOLDERS)); \
+    sbin dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk $(BOARD_ROOT_EXTRA_FOLDERS)); \
     ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
     ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
     ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
@@ -377,4 +377,13 @@
 	$(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \
 		echo $(lib).so >> $@;)
 
+#######################################
+# adb_debug.prop in debug ramdisk
+include $(CLEAR_VARS)
+LOCAL_MODULE := adb_debug.prop
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT)
+include $(BUILD_PREBUILT)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/adb_debug.prop b/rootdir/adb_debug.prop
new file mode 100644
index 0000000..37e2f2d
--- /dev/null
+++ b/rootdir/adb_debug.prop
@@ -0,0 +1,12 @@
+# Note: This file will be loaded with highest priority to override
+# other system properties, if a special ramdisk with "/force_debuggable"
+# is used and the device is unlocked.
+
+# Disable adb authentication to allow test automation on user build GSI
+ro.adb.secure=0
+
+# Allow 'adb root' on user build GSI
+ro.debuggable=1
+
+# Introduce this property to indicate that init has loaded adb_debug.prop
+ro.force.debuggable=1
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 7324ba9..a5db374 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -97,8 +97,7 @@
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
 namespace.media.links = default
-namespace.media.link.default.shared_libs  = libandroid.so
-namespace.media.link.default.shared_libs += libbinder_ndk.so
+namespace.media.link.default.shared_libs  = libbinder_ndk.so
 namespace.media.link.default.shared_libs += libc.so
 namespace.media.link.default.shared_libs += libcgrouprc.so
 namespace.media.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 45e80e1..91a4373 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -177,7 +177,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -620,7 +619,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index a762ba8..11729ee 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -119,7 +119,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -443,7 +442,6 @@
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libandroid.so
 namespace.media.link.default.shared_libs += libbinder_ndk.so
 namespace.media.link.default.shared_libs += libmediametrics.so
 namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b274cf3..dfde53c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -13,9 +13,6 @@
 
 # Cgroups are mounted right before early-init using list from /etc/cgroups.json
 on early-init
-    # Set init and its forked children's oom_adj.
-    write /proc/1/oom_score_adj -1000
-
     # Disable sysrq from keyboard
     write /proc/sys/kernel/sysrq 0
 
@@ -611,6 +608,10 @@
     # IOCTLs on ashmem fds any more.
     setprop sys.use_memfd false
 
+    # Set fscklog permission
+    chown root system /dev/fscklogs/log
+    chmod 0770 /dev/fscklogs/log
+
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
 on zygote-start && property:ro.crypto.state=unencrypted