Merge "liblog: convert to C++"
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index bd5508c..0d0375d 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -24,12 +24,14 @@
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
 #include "adb.h"
 #include "adb_client.h"
+#include "adb_unique_fd.h"
 #include "adb_utils.h"
-#include "android-base/file.h"
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
 #include "client/file_sync_client.h"
 #include "commandline.h"
 #include "fastdeploy.h"
@@ -179,8 +181,8 @@
             return 1;
         }
 
-        int localFd = adb_open(file, O_RDONLY);
-        if (localFd < 0) {
+        unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
+        if (local_fd < 0) {
             fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
             return 1;
         }
@@ -201,19 +203,15 @@
             cmd += " --apex";
         }
 
-        int remoteFd = adb_connect(cmd, &error);
-        if (remoteFd < 0) {
+        unique_fd remote_fd(adb_connect(cmd, &error));
+        if (remote_fd < 0) {
             fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
-            adb_close(localFd);
             return 1;
         }
 
         char buf[BUFSIZ];
-        copy_to_file(localFd, remoteFd);
-        read_status_line(remoteFd, buf, sizeof(buf));
-
-        adb_close(localFd);
-        adb_close(remoteFd);
+        copy_to_file(local_fd.get(), remote_fd.get());
+        read_status_line(remote_fd.get(), buf, sizeof(buf));
 
         if (!strncmp("Success", buf, 7)) {
             fputs(buf, stdout);
@@ -410,14 +408,15 @@
 
     // Create install session
     std::string error;
-    int fd = adb_connect(cmd, &error);
-    if (fd < 0) {
-        fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
-        return EXIT_FAILURE;
-    }
     char buf[BUFSIZ];
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
+    {
+        unique_fd fd(adb_connect(cmd, &error));
+        if (fd < 0) {
+            fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
+            return EXIT_FAILURE;
+        }
+        read_status_line(fd.get(), buf, sizeof(buf));
+    }
 
     int session_id = -1;
     if (!strncmp("Success", buf, 7)) {
@@ -450,27 +449,23 @@
                                             install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
                                             session_id, android::base::Basename(file).c_str());
 
-        int localFd = adb_open(file, O_RDONLY);
-        if (localFd < 0) {
+        unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
+        if (local_fd < 0) {
             fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
             success = 0;
             goto finalize_session;
         }
 
         std::string error;
-        int remoteFd = adb_connect(cmd, &error);
-        if (remoteFd < 0) {
+        unique_fd remote_fd(adb_connect(cmd, &error));
+        if (remote_fd < 0) {
             fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
-            adb_close(localFd);
             success = 0;
             goto finalize_session;
         }
 
-        copy_to_file(localFd, remoteFd);
-        read_status_line(remoteFd, buf, sizeof(buf));
-
-        adb_close(localFd);
-        adb_close(remoteFd);
+        copy_to_file(local_fd.get(), remote_fd.get());
+        read_status_line(remote_fd.get(), buf, sizeof(buf));
 
         if (strncmp("Success", buf, 7)) {
             fprintf(stderr, "adb: failed to write %s\n", file);
@@ -484,13 +479,14 @@
     // Commit session if we streamed everything okay; otherwise abandon
     std::string service = android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
                                                       success ? "commit" : "abandon", session_id);
-    fd = adb_connect(service, &error);
-    if (fd < 0) {
-        fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
-        return EXIT_FAILURE;
+    {
+        unique_fd fd(adb_connect(service, &error));
+        if (fd < 0) {
+            fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
+            return EXIT_FAILURE;
+        }
+        read_status_line(fd.get(), buf, sizeof(buf));
     }
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
 
     if (!strncmp("Success", buf, 7)) {
         fputs(buf, stdout);
@@ -527,14 +523,15 @@
 
     // Create multi-package install session
     std::string error;
-    int fd = adb_connect(multi_package_cmd, &error);
-    if (fd < 0) {
-        fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
-        return EXIT_FAILURE;
-    }
     char buf[BUFSIZ];
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
+    {
+        unique_fd fd(adb_connect(multi_package_cmd, &error));
+        if (fd < 0) {
+            fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
+            return EXIT_FAILURE;
+        }
+        read_status_line(fd.get(), buf, sizeof(buf));
+    }
 
     int parent_session_id = -1;
     if (!strncmp("Success", buf, 7)) {
@@ -566,14 +563,15 @@
     std::string cmd = "";
     for (int i = first_apk; i < argc; i++) {
         // Create individual install session
-        fd = adb_connect(individual_cmd, &error);
-        if (fd < 0) {
-            fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
-            goto finalize_multi_package_session;
-        }
         char buf[BUFSIZ];
-        read_status_line(fd, buf, sizeof(buf));
-        adb_close(fd);
+        {
+            unique_fd fd(adb_connect(individual_cmd, &error));
+            if (fd < 0) {
+                fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
+                goto finalize_multi_package_session;
+            }
+            read_status_line(fd.get(), buf, sizeof(buf));
+        }
 
         int session_id = -1;
         if (!strncmp("Success", buf, 7)) {
@@ -605,25 +603,21 @@
                                             install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
                                             session_id, i, android::base::Basename(file).c_str());
 
-        int localFd = adb_open(file, O_RDONLY);
-        if (localFd < 0) {
+        unique_fd local_fd(adb_open(file, O_RDONLY | O_CLOEXEC));
+        if (local_fd < 0) {
             fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
             goto finalize_multi_package_session;
         }
 
         std::string error;
-        int remoteFd = adb_connect(cmd, &error);
-        if (remoteFd < 0) {
+        unique_fd remote_fd(adb_connect(cmd, &error));
+        if (remote_fd < 0) {
             fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
-            adb_close(localFd);
             goto finalize_multi_package_session;
         }
 
-        copy_to_file(localFd, remoteFd);
-        read_status_line(remoteFd, buf, sizeof(buf));
-
-        adb_close(localFd);
-        adb_close(remoteFd);
+        copy_to_file(local_fd.get(), remote_fd.get());
+        read_status_line(remote_fd.get(), buf, sizeof(buf));
 
         if (strncmp("Success", buf, 7)) {
             fprintf(stderr, "adb: failed to write %s\n", file);
@@ -636,13 +630,14 @@
 
     cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
                                       parent_session_id, all_session_ids.c_str());
-    fd = adb_connect(cmd, &error);
-    if (fd < 0) {
-        fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
-        goto finalize_multi_package_session;
+    {
+        unique_fd fd(adb_connect(cmd, &error));
+        if (fd < 0) {
+            fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
+            goto finalize_multi_package_session;
+        }
+        read_status_line(fd.get(), buf, sizeof(buf));
     }
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
 
     if (strncmp("Success", buf, 7)) {
         fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
@@ -658,13 +653,14 @@
     std::string service =
             android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
                                         success == 0 ? "commit" : "abandon", parent_session_id);
-    fd = adb_connect(service, &error);
-    if (fd < 0) {
-        fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
-        return EXIT_FAILURE;
+    {
+        unique_fd fd(adb_connect(service, &error));
+        if (fd < 0) {
+            fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
+            return EXIT_FAILURE;
+        }
+        read_status_line(fd.get(), buf, sizeof(buf));
     }
-    read_status_line(fd, buf, sizeof(buf));
-    adb_close(fd);
 
     if (!strncmp("Success", buf, 7)) {
         fputs(buf, stdout);
@@ -681,13 +677,12 @@
         service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
                                               session_ids[i]);
         fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
-        fd = adb_connect(service, &error);
+        unique_fd fd(adb_connect(service, &error));
         if (fd < 0) {
             fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
             continue;
         }
-        read_status_line(fd, buf, sizeof(buf));
-        adb_close(fd);
+        read_status_line(fd.get(), buf, sizeof(buf));
     }
     return EXIT_FAILURE;
 }
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index bf58315..d9f2837 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -99,6 +99,11 @@
         "fs_mgr_boot_config.cpp",
         "fs_mgr_slotselect.cpp",
     ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
     export_include_dirs: ["include_fstab"],
     header_libs: ["libbase_headers"],
 }
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index 960410c..8784c94 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -53,9 +53,13 @@
     $ adb disable-verity
     $ adb reboot
 
-can be replaced with:
+*or*
 
-    $ adb reboot -R
+    $ adb remount
+
+can be replaced in both places with:
+
+    $ adb remount -R
 
 which will not reboot if everything is already prepared and ready
 to go.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9f6c550..785f9a2 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -954,6 +954,17 @@
     std::map<std::string, std::string> device_map_;
 };
 
+static bool IsMountPointMounted(const std::string& mount_point) {
+    // Check if this is already mounted.
+    Fstab fstab;
+    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+        return false;
+    }
+    auto it = std::find_if(fstab.begin(), fstab.end(),
+                           [&](const auto& entry) { return entry.mount_point == mount_point; });
+    return it != fstab.end();
+}
+
 // When multiple fstab records share the same mount_point, it will try to mount each
 // one in turn, and ignore any duplicates after a first successful mount.
 // Returns -1 on error, and  FS_MGR_MNTALL_* otherwise.
@@ -970,9 +981,18 @@
     for (size_t i = 0; i < fstab->size(); i++) {
         auto& current_entry = (*fstab)[i];
 
+        // If a filesystem should have been mounted in the first stage, we
+        // ignore it here. With one exception, if the filesystem is
+        // formattable, then it can only be formatted in the second stage,
+        // so we allow it to mount here.
+        if (current_entry.fs_mgr_flags.first_stage_mount &&
+            (!current_entry.fs_mgr_flags.formattable ||
+             IsMountPointMounted(current_entry.mount_point))) {
+            continue;
+        }
+
         // Don't mount entries that are managed by vold or not for the mount mode.
         if (current_entry.fs_mgr_flags.vold_managed || current_entry.fs_mgr_flags.recovery_only ||
-            current_entry.fs_mgr_flags.first_stage_mount ||
             ((mount_mode == MOUNT_MODE_LATE) && !current_entry.fs_mgr_flags.late_mount) ||
             ((mount_mode == MOUNT_MODE_EARLY) && current_entry.fs_mgr_flags.late_mount)) {
             continue;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index a849578..825109f 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -378,7 +378,7 @@
   D=`echo / /
      echo "${D}" | grep -v /dev/root`
 fi
-D=`echo "${D}" | cut -s -d' ' -f1`
+D=`echo "${D}" | cut -s -d' ' -f1 | sort -u`
 D=`adb_sh df -k ${D} </dev/null`
 echo "${D}"
 if [ X"${D}" = X"${D##* 100[%] }" ]; then
@@ -506,7 +506,9 @@
     echo "${D}" &&
     echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
     die  "overlay takeover after remount"
-  !(adb_sh grep "^overlay " /proc/mounts </dev/null | grep -v "^overlay /vendor/..* overlay ro," | grep " overlay ro,") &&
+  !(adb_sh grep "^overlay " /proc/mounts </dev/null |
+    grep -v "^overlay /\(vendor\|system\)/..* overlay ro," |
+    grep " overlay ro,") &&
     !(adb_sh grep " rw," /proc/mounts </dev/null |
       skip_administrative_mounts data) ||
     die "remount overlayfs missed a spot (ro)"
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index a1519da..06c8176 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -26,6 +26,8 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
+
+#include <algorithm>
 #include <memory>
 
 #include <android-base/file.h>
@@ -476,10 +478,16 @@
 
         while ((entry = readdir(dir.get()))) {
             const char* name = entry->d_name;
+            std::vector<String8>::iterator itIgnoreName;
 
             if (!strcmp(name, ".") || !strcmp(name, ".."))
                 continue;
 
+            itIgnoreName = find(hc->ignorePowerSupplyNames.begin(),
+                                hc->ignorePowerSupplyNames.end(), String8(name));
+            if (itIgnoreName != hc->ignorePowerSupplyNames.end())
+                continue;
+
             // Look for "type" file in each subdirectory
             path.clear();
             path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name);
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index c01e8d7..a900071 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -22,6 +22,8 @@
 #include <utils/Errors.h>
 #include <utils/String8.h>
 
+#include <vector>
+
 // periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
 // which healthd wakes up to poll health state and perform periodic chores,
 // in units of seconds:
@@ -71,6 +73,7 @@
     int (*energyCounter)(int64_t *);
     int boot_min_cap;
     bool (*screen_on)(android::BatteryProperties *props);
+    std::vector<android::String8> ignorePowerSupplyNames;
 };
 
 enum EventWakeup {
diff --git a/init/README.md b/init/README.md
index 8d47e0a..3a7c71c 100644
--- a/init/README.md
+++ b/init/README.md
@@ -482,9 +482,8 @@
   -f: force installation of the module even if the version of the running kernel
   and the version of the kernel for which the module was compiled do not match.
 
-`load_all_props`
-> Loads properties from /system, /vendor, et cetera.
-  This is included in the default init.rc.
+`load_system_props`
+> (This action is deprecated and no-op.)
 
 `load_persist_props`
 > Loads persistent properties when /data has been decrypted.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 4a66e46..43a520f 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -972,7 +972,7 @@
 }
 
 static Result<Success> do_load_system_props(const BuiltinArguments& args) {
-    load_system_props();
+    LOG(INFO) << "deprecated action `load_system_props` called.";
     return Success();
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index dc46a82..d360fdd 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -451,6 +451,8 @@
     // Also, binder can't be used by recovery.
 #ifndef RECOVERY
     android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
+    android::ProcessState::self()->setCallRestriction(
+            ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY);
 #endif
     return Success();
 }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5328869..3199d45 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -699,22 +699,6 @@
     }
 }
 
-void property_load_boot_defaults() {
-    if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
-        // Try recovery path
-        if (!load_properties_from_file("/prop.default", NULL)) {
-            // Try legacy path
-            load_properties_from_file("/default.prop", NULL);
-        }
-    }
-    load_properties_from_file("/product/build.prop", NULL);
-    load_properties_from_file("/product_services/build.prop", NULL);
-    load_properties_from_file("/odm/default.prop", NULL);
-    load_properties_from_file("/vendor/default.prop", NULL);
-
-    update_sys_usb_config();
-}
-
 static void load_override_properties() {
     if (ALLOW_LOCAL_PROP_OVERRIDE) {
         load_properties_from_file("/data/local.prop", NULL);
@@ -779,12 +763,29 @@
     close(fd);
 }
 
-void load_system_props() {
+void property_load_boot_defaults() {
+    // TODO(b/117892318): merge prop.default and build.prop files into one
+    // TODO(b/122864654): read the prop files from all partitions and then
+    // resolve the duplication by their origin so that RO and non-RO properties
+    // have a consistent overriding order.
+    if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
+        // Try recovery path
+        if (!load_properties_from_file("/prop.default", NULL)) {
+            // Try legacy path
+            load_properties_from_file("/default.prop", NULL);
+        }
+    }
+    load_properties_from_file("/product/build.prop", NULL);
+    load_properties_from_file("/product_services/build.prop", NULL);
+    load_properties_from_file("/odm/default.prop", NULL);
+    load_properties_from_file("/vendor/default.prop", NULL);
     load_properties_from_file("/system/build.prop", NULL);
     load_properties_from_file("/odm/build.prop", NULL);
     load_properties_from_file("/vendor/build.prop", NULL);
     load_properties_from_file("/factory/factory.prop", "ro.*");
     load_recovery_id_prop();
+
+    update_sys_usb_config();
 }
 
 static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
diff --git a/init/service.cpp b/init/service.cpp
index eec55c3..f3eafe4 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -406,7 +406,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) || classnames_.count("updatable")) && !(flags_ & SVC_RESTART)) {
+    if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) {
         if (now < time_crashed_ + 4min) {
             if (++crash_count_ > 4) {
                 if (flags_ & SVC_CRITICAL) {
diff --git a/janitors/OWNERS b/janitors/OWNERS
new file mode 100644
index 0000000..0610b41
--- /dev/null
+++ b/janitors/OWNERS
@@ -0,0 +1,4 @@
+# OWNERS file for projects that don't really have owners so much as volunteer janitors.
+enh@google.com
+hhb@google.com
+narayan@google.com
diff --git a/libmeminfo/include/meminfo/meminfo.h b/libmeminfo/include/meminfo/meminfo.h
index 5ee32d4..2fc7867 100644
--- a/libmeminfo/include/meminfo/meminfo.h
+++ b/libmeminfo/include/meminfo/meminfo.h
@@ -72,15 +72,10 @@
         : start(s), end(e), offset(off), flags(f), name(n) {}
     ~Vma() = default;
 
-    void clear() {
-        memset(&usage, 0, sizeof(usage));
-        memset(&wss, 0, sizeof(wss));
-    }
+    void clear() { memset(&usage, 0, sizeof(usage)); }
 
     // Memory usage of this mapping.
     MemUsage usage;
-    // Working set within this mapping.
-    MemUsage wss;
 };
 
 }  // namespace meminfo
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 0bfd80f..0b66074 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -64,7 +64,12 @@
     //   private_dirty
     //   SwapPss
     // All other fields of MemUsage are zeroed.
-    bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const;
+    bool SmapsOrRollup(MemUsage* stats) const;
+
+    // Used to parse either of /proc/<pid>/{smaps, smaps_rollup} and record the process's
+    // Pss.
+    // Returns 'true' on success and the value of Pss in the out parameter.
+    bool SmapsOrRollupPss(uint64_t* pss) const;
 
     const std::vector<uint16_t>& SwapOffsets();
 
@@ -82,7 +87,6 @@
     std::vector<Vma> maps_;
 
     MemUsage usage_;
-    MemUsage wss_;
     std::vector<uint16_t> swap_offsets_;
 };
 
@@ -90,10 +94,21 @@
 // same format as /proc/<pid>/smaps. Returns 'false' if the file is malformed.
 bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback);
 
+// Returns if the kernel supports /proc/<pid>/smaps_rollup. Assumes that the
+// calling process has access to the /proc/<pid>/smaps_rollup.
+// Returns 'false' if the calling process has no permission to read the file if it exists
+// of if the file doesn't exist.
+bool IsSmapsRollupSupported(pid_t pid);
+
 // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly
 // from a file. The file MUST be in the same format as /proc/<pid>/smaps
 // or /proc/<pid>/smaps_rollup
 bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats);
 
+// Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly
+// from a file and returns total Pss in kB. The file MUST be in the same format
+// as /proc/<pid>/smaps or /proc/<pid>/smaps_rollup
+bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss);
+
 }  // namespace meminfo
 }  // namespace android
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 20ed3bf..7d85dd2 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -284,13 +284,13 @@
     EXPECT_EQ(swap_offsets.size(), 0);
 }
 
-TEST(TestProcMemInfo, SmapsOrRollupReturn) {
-    // if /proc/<pid>/smaps_rollup file exists, .SmapsRollup() must return true;
-    // false otherwise
+TEST(TestProcMemInfo, IsSmapsSupportedTest) {
     std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid);
-    ProcMemInfo proc_mem(pid);
-    MemUsage stats;
-    EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(true, &stats));
+    bool supported = IsSmapsRollupSupported(pid);
+    EXPECT_EQ(!access(path.c_str(), F_OK | R_OK), supported);
+    // Second call must return what the first one returned regardless of the pid parameter.
+    // So, deliberately pass invalid pid.
+    EXPECT_EQ(supported, IsSmapsRollupSupported(-1));
 }
 
 TEST(TestProcMemInfo, SmapsOrRollupTest) {
@@ -365,6 +365,50 @@
     EXPECT_EQ(stats.swap_pss, 70);
 }
 
+TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) {
+    // This is a made up smaps for the test
+    std::string smaps =
+            R"smaps(12c00000-13440000 rw-p 00000000 00:00 0                                  [anon:dalvik-main space (region space)]
+Name:           [anon:dalvik-main space (region space)]
+Size:               8448 kB
+KernelPageSize:        4 kB
+MMUPageSize:           4 kB
+Rss:                2652 kB
+Pss:                2652 kB
+Shared_Clean:        840 kB
+Shared_Dirty:         40 kB
+Private_Clean:        84 kB
+Private_Dirty:      2652 kB
+Referenced:         2652 kB
+Anonymous:          2652 kB
+AnonHugePages:         0 kB
+ShmemPmdMapped:        0 kB
+Shared_Hugetlb:        0 kB
+Private_Hugetlb:       0 kB
+Swap:                102 kB
+SwapPss:              70 kB
+Locked:             2652 kB
+VmFlags: rd wr mr mw me ac 
+)smaps";
+
+    TemporaryFile tf;
+    ASSERT_TRUE(tf.fd != -1);
+    ASSERT_TRUE(::android::base::WriteStringToFd(smaps, tf.fd));
+
+    uint64_t pss;
+    ASSERT_EQ(SmapsOrRollupPssFromFile(tf.path, &pss), true);
+    EXPECT_EQ(pss, 2652);
+}
+
+TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) {
+    std::string exec_dir = ::android::base::GetExecutableDirectory();
+    std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
+
+    uint64_t pss;
+    ASSERT_EQ(SmapsOrRollupPssFromFile(path, &pss), true);
+    EXPECT_EQ(pss, 19119);
+}
+
 TEST(TestProcMemInfo, ForEachVmaFromFileTest) {
     std::string exec_dir = ::android::base::GetExecutableDirectory();
     std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
@@ -374,6 +418,9 @@
     auto collect_vmas = [&](const Vma& v) { vmas.push_back(v); };
     ASSERT_TRUE(ForEachVmaFromFile(path, collect_vmas));
 
+    // We should get a total of 6 vmas
+    ASSERT_EQ(vmas.size(), 6);
+
     // Expect values to be equal to what we have in testdata1/smaps_short
     // Check for sizes first
     ASSERT_EQ(vmas[0].usage.vss, 32768);
@@ -468,6 +515,8 @@
     auto vmas = proc_mem.Smaps(path);
 
     ASSERT_FALSE(vmas.empty());
+    // We should get a total of 6 vmas
+    ASSERT_EQ(vmas.size(), 6);
 
     // Expect values to be equal to what we have in testdata1/smaps_short
     // Check for sizes first
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index 1f8db1a..d6332a3 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -21,6 +21,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#include <atomic>
 #include <fstream>
 #include <iostream>
 #include <memory>
@@ -157,14 +158,14 @@
     if (!get_wss_) {
         LOG(WARNING) << "Trying to read process working set for " << pid_
                      << " using invalid object";
-        return wss_;
+        return usage_;
     }
 
     if (maps_.empty() && !ReadMaps(get_wss_)) {
         LOG(ERROR) << "Failed to get working set for Process " << pid_;
     }
 
-    return wss_;
+    return usage_;
 }
 
 bool ProcMemInfo::ForEachVma(const VmaCallback& callback) {
@@ -172,11 +173,17 @@
     return ForEachVmaFromFile(path, callback);
 }
 
-bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const {
-    std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_,
-                                                     use_rollup ? "smaps_rollup" : "smaps");
+bool ProcMemInfo::SmapsOrRollup(MemUsage* stats) const {
+    std::string path = ::android::base::StringPrintf(
+            "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps");
     return SmapsOrRollupFromFile(path, stats);
-};
+}
+
+bool ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) const {
+    std::string path = ::android::base::StringPrintf(
+            "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps");
+    return SmapsOrRollupPssFromFile(path, pss);
+}
 
 const std::vector<uint16_t>& ProcMemInfo::SwapOffsets() {
     if (get_wss_) {
@@ -228,11 +235,7 @@
             maps_.clear();
             return false;
         }
-        if (get_wss) {
-            add_mem_usage(&wss_, vma.wss);
-        } else {
-            add_mem_usage(&usage_, vma.usage);
-        }
+        add_mem_usage(&usage_, vma.usage);
     }
 
     return true;
@@ -300,31 +303,20 @@
             // This effectively makes vss = rss for the working set is requested.
             // The libpagemap implementation returns vss > rss for
             // working set, which doesn't make sense.
-            vma.wss.vss += pagesz;
-            vma.wss.rss += pagesz;
-            vma.wss.uss += is_private ? pagesz : 0;
-            vma.wss.pss += pagesz / pg_counts[i];
-            if (is_private) {
-                vma.wss.private_dirty += is_dirty ? pagesz : 0;
-                vma.wss.private_clean += is_dirty ? 0 : pagesz;
-            } else {
-                vma.wss.shared_dirty += is_dirty ? pagesz : 0;
-                vma.wss.shared_clean += is_dirty ? 0 : pagesz;
-            }
+            vma.usage.vss += pagesz;
+        }
+
+        vma.usage.rss += pagesz;
+        vma.usage.uss += is_private ? pagesz : 0;
+        vma.usage.pss += pagesz / pg_counts[i];
+        if (is_private) {
+            vma.usage.private_dirty += is_dirty ? pagesz : 0;
+            vma.usage.private_clean += is_dirty ? 0 : pagesz;
         } else {
-            vma.usage.rss += pagesz;
-            vma.usage.uss += is_private ? pagesz : 0;
-            vma.usage.pss += pagesz / pg_counts[i];
-            if (is_private) {
-                vma.usage.private_dirty += is_dirty ? pagesz : 0;
-                vma.usage.private_clean += is_dirty ? 0 : pagesz;
-            } else {
-                vma.usage.shared_dirty += is_dirty ? pagesz : 0;
-                vma.usage.shared_clean += is_dirty ? 0 : pagesz;
-            }
+            vma.usage.shared_dirty += is_dirty ? pagesz : 0;
+            vma.usage.shared_clean += is_dirty ? 0 : pagesz;
         }
     }
-
     return true;
 }
 
@@ -338,8 +330,9 @@
     char* line = nullptr;
     bool parsing_vma = false;
     ssize_t line_len;
+    size_t line_alloc = 0;
     Vma vma;
-    while ((line_len = getline(&line, 0, fp.get())) > 0) {
+    while ((line_len = getline(&line, &line_alloc, fp.get())) > 0) {
         // Make sure the line buffer terminates like a C string for ReadMapFile
         line[line_len] = '\0';
 
@@ -382,15 +375,41 @@
     return true;
 }
 
+enum smaps_rollup_support { UNTRIED, SUPPORTED, UNSUPPORTED };
+
+static std::atomic<smaps_rollup_support> g_rollup_support = UNTRIED;
+
+bool IsSmapsRollupSupported(pid_t pid) {
+    // Similar to OpenSmapsOrRollup checks from android_os_Debug.cpp, except
+    // the method only checks if rollup is supported and returns the status
+    // right away.
+    enum smaps_rollup_support rollup_support = g_rollup_support.load(std::memory_order_relaxed);
+    if (rollup_support != UNTRIED) {
+        return rollup_support == SUPPORTED;
+    }
+    std::string rollup_file = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid);
+    if (access(rollup_file.c_str(), F_OK | R_OK)) {
+        // No check for errno = ENOENT necessary here. The caller MUST fallback to
+        // using /proc/<pid>/smaps instead anyway.
+        g_rollup_support.store(UNSUPPORTED, std::memory_order_relaxed);
+        return false;
+    }
+
+    g_rollup_support.store(SUPPORTED, std::memory_order_relaxed);
+    LOG(INFO) << "Using smaps_rollup for pss collection";
+    return true;
+}
+
 bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) {
     auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
     if (fp == nullptr) {
         return false;
     }
 
-    char line[1024];
+    char* line = nullptr;
+    size_t line_alloc = 0;
     stats->clear();
-    while (fgets(line, sizeof(line), fp.get()) != nullptr) {
+    while (getline(&line, &line_alloc, fp.get()) > 0) {
         switch (line[0]) {
             case 'P':
                 if (strncmp(line, "Pss:", 4) == 0) {
@@ -423,6 +442,28 @@
         }
     }
 
+    // free getline() managed buffer
+    free(line);
+    return true;
+}
+
+bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss) {
+    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (fp == nullptr) {
+        return false;
+    }
+    *pss = 0;
+    char* line = nullptr;
+    size_t line_alloc = 0;
+    while (getline(&line, &line_alloc, fp.get()) > 0) {
+        uint64_t v;
+        if (sscanf(line, "Pss: %" SCNu64 " kB", &v) == 1) {
+            *pss += v;
+        }
+    }
+
+    // free getline() managed buffer
+    free(line);
     return true;
 }
 
diff --git a/libmeminfo/tools/procmem.cpp b/libmeminfo/tools/procmem.cpp
index b9b174d..47881ed 100644
--- a/libmeminfo/tools/procmem.cpp
+++ b/libmeminfo/tools/procmem.cpp
@@ -98,7 +98,7 @@
     std::stringstream ss;
     print_header(ss);
     for (auto& vma : maps) {
-        const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage;
+        const MemUsage& vma_stats = vma.usage;
         if (hide_zeroes && vma_stats.rss == 0) {
             continue;
         }
@@ -116,14 +116,14 @@
 int main(int argc, char* argv[]) {
     int opt;
     auto pss_sort = [](const Vma& a, const Vma& b) {
-        uint64_t pss_a = show_wss ? a.wss.pss : a.usage.pss;
-        uint64_t pss_b = show_wss ? b.wss.pss : b.usage.pss;
+        uint64_t pss_a = a.usage.pss;
+        uint64_t pss_b = b.usage.pss;
         return pss_a > pss_b;
     };
 
     auto uss_sort = [](const Vma& a, const Vma& b) {
-        uint64_t uss_a = show_wss ? a.wss.uss : a.usage.uss;
-        uint64_t uss_b = show_wss ? b.wss.uss : b.usage.uss;
+        uint64_t uss_a = a.usage.uss;
+        uint64_t uss_b = b.usage.uss;
         return uss_a > uss_b;
     };
 
@@ -182,7 +182,7 @@
     }
 
     ProcMemInfo proc(pid, show_wss);
-    const MemUsage& proc_stats = show_wss ? proc.Wss() : proc.Usage();
+    const MemUsage& proc_stats = proc.Usage();
     std::vector<Vma> maps(proc.Maps());
     if (sort_func != nullptr) {
         std::sort(maps.begin(), maps.end(), sort_func);
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index a751722..21a684c 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -465,7 +465,7 @@
         }
 
         // Skip processes with no memory mappings
-        uint64_t vss = show_wss ? proc.Wss().vss : proc.Usage().vss;
+        uint64_t vss = proc.Usage().vss;
         if (vss == 0) return true;
 
         // collect swap_offset counts from all processes in 1st pass
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 59cd033..c54570e 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -17,6 +17,15 @@
         "liblog",
     ],
 
+    target: {
+        android: {
+            version_script: "libnativebridge.map.txt",
+        },
+        linux: {
+            version_script: "libnativebridge.map.txt",
+        },
+    },
+
     stubs: {
         symbol_file: "libnativebridge.map.txt",
         versions: ["1"],
diff --git a/libnativebridge/OWNERS b/libnativebridge/OWNERS
index f2cc942..6f0824b 100644
--- a/libnativebridge/OWNERS
+++ b/libnativebridge/OWNERS
@@ -1 +1,2 @@
 dimitry@google.com
+eaeltsin@google.com
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 17983bc..8903b72 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -23,4 +23,20 @@
         "llndk.libraries.txt",
         "vndksp.libraries.txt",
     ],
+    target: {
+        android: {
+            version_script: "libnativeloader.map.txt",
+        },
+    },
+    stubs: {
+        symbol_file: "libnativeloader.map.txt",
+        versions: ["1"],
+    },
+}
+
+cc_library_headers {
+    name: "libnativeloader-dummy-headers",
+
+    host_supported: true,
+    export_include_dirs: ["include"],
 }
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 43c9329..ca026b3 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -18,6 +18,7 @@
 #define __ANDROID_DLEXT_NAMESPACES_H__
 
 #include <android/dlext.h>
+#include <stdbool.h>
 
 __BEGIN_DECLS
 
@@ -84,12 +85,9 @@
  * If a library or any of its dependencies are outside of the permitted_when_isolated_path
  * and search_path, and it is not part of the public namespace dlopen will fail.
  */
-extern struct android_namespace_t* android_create_namespace(const char* name,
-                                                            const char* ld_library_path,
-                                                            const char* default_library_path,
-                                                            uint64_t type,
-                                                            const char* permitted_when_isolated_path,
-                                                            android_namespace_t* parent);
+extern struct android_namespace_t* android_create_namespace(
+    const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
+    const char* permitted_when_isolated_path, struct android_namespace_t* parent);
 
 /*
  * Creates a link between namespaces. Every link has list of sonames of
@@ -107,8 +105,8 @@
  *      step will not go deeper into linked namespaces for this library but
  *      will do so for DT_NEEDED libraries.
  */
-extern bool android_link_namespaces(android_namespace_t* from,
-                                    android_namespace_t* to,
+extern bool android_link_namespaces(struct android_namespace_t* from,
+                                    struct android_namespace_t* to,
                                     const char* shared_libs_sonames);
 
 /*
@@ -124,7 +122,7 @@
  */
 extern void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size);
 
-extern android_namespace_t* android_get_exported_namespace(const char* name);
+extern struct android_namespace_t* android_get_exported_namespace(const char* name);
 
 __END_DECLS
 
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index c1d9d2a..af53dc5 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -17,14 +17,21 @@
 #ifndef NATIVE_LOADER_H_
 #define NATIVE_LOADER_H_
 
-#include "jni.h"
+#include <stdbool.h>
 #include <stdint.h>
-#include <string>
+#include "jni.h"
 #if defined(__ANDROID__)
 #include <android/dlext.h>
 #endif
 
+#ifdef __cplusplus
 namespace android {
+extern "C" {
+#endif  // __cplusplus
+
+// README: the char** error message parameter being passed
+// to the methods below need to be freed through calling NativeLoaderFreeErrorMessage.
+// It's the caller's responsibility to call that method.
 
 __attribute__((visibility("default")))
 void InitializeNativeLoader();
@@ -38,42 +45,39 @@
                                    jstring library_path,
                                    jstring permitted_path);
 
-__attribute__((visibility("default")))
-void* OpenNativeLibrary(JNIEnv* env,
-                        int32_t target_sdk_version,
-                        const char* path,
-                        jobject class_loader,
-                        jstring library_path,
-                        bool* needs_native_bridge,
-                        std::string* error_msg);
+__attribute__((visibility("default"))) void* OpenNativeLibrary(
+    JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader,
+    jstring library_path, bool* needs_native_bridge, char** error_msg);
 
 __attribute__((visibility("default"))) bool CloseNativeLibrary(void* handle,
                                                                const bool needs_native_bridge,
-                                                               std::string* error_msg);
+                                                               char** error_msg);
+
+__attribute__((visibility("default"))) void NativeLoaderFreeErrorMessage(char* msg);
 
 #if defined(__ANDROID__)
 // Look up linker namespace by class_loader. Returns nullptr if
 // there is no namespace associated with the class_loader.
 // TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function.
-__attribute__((visibility("default")))
-android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
-// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
-class NativeLoaderNamespace;
-__attribute__((visibility("default")))
-NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(
+__attribute__((visibility("default"))) struct android_namespace_t* FindNamespaceByClassLoader(
     JNIEnv* env, jobject class_loader);
+// That version works with native bridge namespaces, but requires use of OpenNativeLibrary.
+struct NativeLoaderNamespace;
+__attribute__((visibility("default"))) struct NativeLoaderNamespace*
+FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
 // Load library.  Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does
 // not require access to JNIEnv either.
-__attribute__((visibility("default")))
-void* OpenNativeLibrary(NativeLoaderNamespace* ns,
-                        const char* path,
-                        bool* needs_native_bridge,
-                        std::string* error_msg);
+__attribute__((visibility("default"))) void* OpenNativeLibraryInNamespace(
+    struct NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
+    char** error_msg);
 #endif
 
 __attribute__((visibility("default")))
 void ResetNativeLoader();
 
-};  // namespace android
+#ifdef __cplusplus
+}  // extern "C"
+}  // namespace android
+#endif  // __cplusplus
 
 #endif  // NATIVE_BRIDGE_H_
diff --git a/libnativeloader/libnativeloader.map.txt b/libnativeloader/libnativeloader.map.txt
new file mode 100644
index 0000000..40c30bd
--- /dev/null
+++ b/libnativeloader/libnativeloader.map.txt
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# TODO(b/122710865): Prune these uses once the runtime APEX is complete.
+LIBNATIVELOADER_1 {
+  global:
+    OpenNativeLibrary;
+    InitializeNativeLoader;
+    ResetNativeLoader;
+    CloseNativeLibrary;
+    OpenNativeLibraryInNamespace;
+    FindNamespaceByClassLoader;
+    FindNativeLoaderNamespaceByClassLoader;
+    CreateClassLoaderNamespace;
+    NativeLoaderFreeErrorMessage;
+  local:
+    *;
+};
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index de7ea08..f231afa 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -52,7 +52,7 @@
 namespace android {
 
 #if defined(__ANDROID__)
-class NativeLoaderNamespace {
+struct NativeLoaderNamespace {
  public:
   NativeLoaderNamespace()
       : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
@@ -151,14 +151,9 @@
  public:
   LibraryNamespaces() : initialized_(false) { }
 
-  NativeLoaderNamespace* Create(JNIEnv* env,
-                                uint32_t target_sdk_version,
-                                jobject class_loader,
-                                bool is_shared,
-                                bool is_for_vendor,
-                                jstring java_library_path,
-                                jstring java_permitted_path,
-                                std::string* error_msg) {
+  NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
+                                bool is_shared, bool is_for_vendor, jstring java_library_path,
+                                jstring java_permitted_path, std::string* error_msg) {
     std::string library_path; // empty string by default.
 
     if (java_library_path != nullptr) {
@@ -628,13 +623,9 @@
   return nullptr;
 }
 
-void* OpenNativeLibrary(JNIEnv* env,
-                        int32_t target_sdk_version,
-                        const char* path,
-                        jobject class_loader,
-                        jstring library_path,
-                        bool* needs_native_bridge,
-                        std::string* error_msg) {
+void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
+                        jobject class_loader, jstring library_path, bool* needs_native_bridge,
+                        char** error_msg) {
 #if defined(__ANDROID__)
   UNUSED(target_sdk_version);
   if (class_loader == nullptr) {
@@ -652,19 +643,16 @@
   if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) {
     // This is the case where the classloader was not created by ApplicationLoaders
     // In this case we create an isolated not-shared namespace for it.
-    if ((ns = g_namespaces->Create(env,
-                                   target_sdk_version,
-                                   class_loader,
-                                   false /* is_shared */,
-                                   false /* is_for_vendor */,
-                                   library_path,
-                                   nullptr,
-                                   error_msg)) == nullptr) {
+    std::string create_error_msg;
+    if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */,
+                                   false /* is_for_vendor */, library_path, nullptr,
+                                   &create_error_msg)) == nullptr) {
+      *error_msg = strdup(create_error_msg.c_str());
       return nullptr;
     }
   }
 
-  return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg);
+  return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg);
 #else
   UNUSED(env, target_sdk_version, class_loader);
 
@@ -705,35 +693,40 @@
       if (handle != nullptr) {
         return handle;
       }
-      *error_msg = NativeBridgeGetError();
+      *error_msg = strdup(NativeBridgeGetError());
     } else {
-      *error_msg = dlerror();
+      *error_msg = strdup(dlerror());
     }
   }
   return nullptr;
 #endif
 }
 
-bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, std::string* error_msg) {
+bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) {
   bool success;
   if (needs_native_bridge) {
     success = (NativeBridgeUnloadLibrary(handle) == 0);
     if (!success) {
-      *error_msg = NativeBridgeGetError();
+      *error_msg = strdup(NativeBridgeGetError());
     }
   } else {
     success = (dlclose(handle) == 0);
     if (!success) {
-      *error_msg = dlerror();
+      *error_msg = strdup(dlerror());
     }
   }
 
   return success;
 }
 
+void NativeLoaderFreeErrorMessage(char* msg) {
+  // The error messages get allocated through strdup, so we must call free on them.
+  free(msg);
+}
+
 #if defined(__ANDROID__)
-void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge,
-                        std::string* error_msg) {
+void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
+                                   bool* needs_native_bridge, char** error_msg) {
   if (ns->is_android_namespace()) {
     android_dlextinfo extinfo;
     extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
@@ -741,14 +734,14 @@
 
     void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
     if (handle == nullptr) {
-      *error_msg = dlerror();
+      *error_msg = strdup(dlerror());
     }
     *needs_native_bridge = false;
     return handle;
   } else {
     void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
     if (handle == nullptr) {
-      *error_msg = NativeBridgeGetError();
+      *error_msg = strdup(NativeBridgeGetError());
     }
     *needs_native_bridge = true;
     return handle;
diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp
index d528f30..1464e39 100644
--- a/libnativeloader/test/Android.bp
+++ b/libnativeloader/test/Android.bp
@@ -69,3 +69,14 @@
         "libbase",
     ],
 }
+
+// Build the test for the C API.
+cc_test {
+    name: "libnativeloader-api-tests",
+    host_supported: true,
+    test_per_src: true,
+    srcs: [
+        "api_test.c",
+    ],
+    header_libs: ["libnativeloader-dummy-headers"],
+}
diff --git a/libnativeloader/test/api_test.c b/libnativeloader/test/api_test.c
new file mode 100644
index 0000000..e7025fd
--- /dev/null
+++ b/libnativeloader/test/api_test.c
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/* The main purpose of this test is to ensure this C header compiles in C, so
+ * that no C++ features inadvertently leak into the C ABI. */
+#include "nativeloader/native_loader.h"
+
+int main(int argc, char** argv) {
+  (void)argc;
+  (void)argv;
+  return 0;
+}
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index d0af94a..709e6c9 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -177,14 +177,14 @@
 template <typename EhdrType, typename PhdrType>
 uint64_t ElfInterface::GetLoadBias(Memory* memory) {
   EhdrType ehdr;
-  if (!memory->Read(0, &ehdr, sizeof(ehdr))) {
+  if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
     return false;
   }
 
   uint64_t offset = ehdr.e_phoff;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
     PhdrType phdr;
-    if (!memory->Read(offset, &phdr, sizeof(phdr))) {
+    if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
       return 0;
     }
     if (phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
@@ -308,7 +308,7 @@
   // Skip the first header, it's always going to be NULL.
   offset += ehdr.e_shentsize;
   for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
-    if (!memory_->Read(offset, &shdr, sizeof(shdr))) {
+    if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
       return;
     }
 
@@ -320,7 +320,7 @@
         continue;
       }
       uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
-      if (!memory_->Read(str_offset, &str_shdr, sizeof(str_shdr))) {
+      if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
         continue;
       }
       if (str_shdr.sh_type != SHT_STRTAB) {
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
index 14a4e31..f330fe0 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -135,7 +135,7 @@
   Memory* elf_memory = elf->memory();
   // Read from elf memory since it is usually more expensive to read from
   // process memory.
-  if (!elf_memory->Read(rel_pc, &data, sizeof(data))) {
+  if (!elf_memory->ReadFully(rel_pc, &data, sizeof(data))) {
     return false;
   }
 
@@ -160,7 +160,7 @@
 
   // read sc_pc and sc_regs[32] from stack
   uint64_t values[MIPS_REG_LAST];
-  if (!process_memory->Read(regs_[MIPS_REG_SP] + offset, values, sizeof(values))) {
+  if (!process_memory->ReadFully(regs_[MIPS_REG_SP] + offset, values, sizeof(values))) {
     return false;
   }
 
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 7794f81..ca78c38 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "lowmemorykiller"
 
+#include <dirent.h>
 #include <errno.h>
 #include <inttypes.h>
 #include <pwd.h>
@@ -28,18 +29,22 @@
 #include <sys/epoll.h>
 #include <sys/eventfd.h>
 #include <sys/mman.h>
+#include <sys/resource.h>
 #include <sys/socket.h>
 #include <sys/sysinfo.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <cutils/properties.h>
+#include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
 #include <lmkd.h>
 #include <log/log.h>
 #include <log/log_event_list.h>
 #include <log/log_time.h>
+#include <system/thread_defs.h>
 
 #ifdef LMKD_LOG_STATS
 #include "statslog.h"
@@ -1261,6 +1266,41 @@
     return maxprocp;
 }
 
+static void set_process_group_and_prio(int pid, SchedPolicy sp, int prio) {
+    DIR* d;
+    char proc_path[PATH_MAX];
+    struct dirent* de;
+
+    snprintf(proc_path, sizeof(proc_path), "/proc/%d/task", pid);
+    if (!(d = opendir(proc_path))) {
+        ALOGW("Failed to open %s; errno=%d: process pid(%d) might have died", proc_path, errno,
+              pid);
+        return;
+    }
+
+    while ((de = readdir(d))) {
+        int t_pid;
+
+        if (de->d_name[0] == '.') continue;
+        t_pid = atoi(de->d_name);
+
+        if (!t_pid) {
+            ALOGW("Failed to get t_pid for '%s' of pid(%d)", de->d_name, pid);
+            continue;
+        }
+
+        if (setpriority(PRIO_PROCESS, t_pid, prio) && errno != ESRCH) {
+            ALOGW("Unable to raise priority of killing t_pid (%d): errno=%d", t_pid, errno);
+        }
+
+        if (set_cpuset_policy(t_pid, sp)) {
+            ALOGW("Failed to set_cpuset_policy on pid(%d) t_pid(%d) to %d", pid, t_pid, (int)sp);
+            continue;
+        }
+    }
+    closedir(d);
+}
+
 static int last_killed_pid = -1;
 
 /* Kill one process specified by procp.  Returns the size of the process killed */
@@ -1301,6 +1341,9 @@
 
     /* CAP_KILL required */
     r = kill(pid, SIGKILL);
+
+    set_process_group_and_prio(pid, SP_FOREGROUND, ANDROID_PRIORITY_HIGHEST);
+
     inc_killcnt(procp->oomadj);
     ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
         taskname, pid, uid, procp->oomadj, tasksize * page_k);
diff --git a/lmkd/tests/Android.bp b/lmkd/tests/Android.bp
index cbf44e9..4e845fd 100644
--- a/lmkd/tests/Android.bp
+++ b/lmkd/tests/Android.bp
@@ -18,6 +18,7 @@
     shared_libs: [
         "libbase",
         "liblog",
+        "libcutils",
     ],
 
     static_libs: [
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b34399d..372f481 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -117,6 +117,8 @@
     mkdir /mnt/runtime/read/self 0755 root root
     mkdir /mnt/runtime/write 0755 root root
     mkdir /mnt/runtime/write/self 0755 root root
+    mkdir /mnt/runtime/full 0755 root root
+    mkdir /mnt/runtime/full/self 0755 root root
 
     # Symlink to keep legacy apps working in multi-user world
     symlink /storage/self/primary /sdcard
@@ -346,12 +348,6 @@
     trigger boot
 
 on post-fs
-    # Load properties from
-    #     /system/build.prop,
-    #     /odm/build.prop,
-    #     /vendor/build.prop and
-    #     /factory/factory.prop
-    load_system_props
     start vold
     exec - system system -- /system/bin/vdc checkpoint markBootAttempt
 
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
index dc36596..e1de130 100644
--- a/sdcard/sdcard.cpp
+++ b/sdcard/sdcard.cpp
@@ -160,6 +160,7 @@
     std::string dest_path_default = "/mnt/runtime/default/" + label;
     std::string dest_path_read = "/mnt/runtime/read/" + label;
     std::string dest_path_write = "/mnt/runtime/write/" + label;
+    std::string dest_path_full = "/mnt/runtime/full/" + label;
 
     umask(0);
     if (multi_user) {
@@ -172,7 +173,10 @@
                                       default_normal, use_esdfs) ||
             !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid,
                                       multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0027,
-                                      derive_gid, default_normal, use_esdfs)) {
+                                      derive_gid, default_normal, use_esdfs) ||
+            !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_full, uid, gid,
+                                      multi_user, userid, AID_EVERYBODY, 0007, derive_gid,
+                                      default_normal, use_esdfs)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
     } else {
@@ -186,7 +190,10 @@
                                       derive_gid, default_normal, use_esdfs) ||
             !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_write, uid, gid,
                                       multi_user, userid, AID_EVERYBODY, full_write ? 0007 : 0022,
-                                      derive_gid, default_normal, use_esdfs)) {
+                                      derive_gid, default_normal, use_esdfs) ||
+            !sdcardfs_setup_secondary(dest_path_default, source_path, dest_path_full, uid, gid,
+                                      multi_user, userid, AID_EVERYBODY, 0007, derive_gid,
+                                      default_normal, use_esdfs)) {
             LOG(FATAL) << "failed to sdcardfs_setup";
         }
     }