Merge "libdm: Fix race conditions in LoopControl::Attach."
diff --git a/adb/Android.bp b/adb/Android.bp
index f6aede8..6558b1b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -436,7 +436,6 @@
             shared_libs: [
                 "libbootloader_message",
                 "libmdnssd",
-                "libext4_utils",
                 "libfec",
                 "libfs_mgr",
                 "libselinux",
diff --git a/base/include/android-base/expected.h b/base/include/android-base/expected.h
index 6153b77..030ef35e 100644
--- a/base/include/android-base/expected.h
+++ b/base/include/android-base/expected.h
@@ -256,7 +256,8 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(
+      std::is_nothrow_move_assignable_v<T>&& std::is_nothrow_move_assignable_v<E>) = default;
 
   template <class U = T _ENABLE_IF(
                 !std::is_void_v<T> &&
@@ -542,7 +543,7 @@
   expected& operator=(const expected& rhs) = default;
 
   // Note for SFNAIE above applies to here as well
-  expected& operator=(expected&& rhs) = default;
+  expected& operator=(expected&& rhs) noexcept(std::is_nothrow_move_assignable_v<E>) = default;
 
   template<class G = E>
   expected& operator=(const unexpected<G>& rhs) {
@@ -633,7 +634,7 @@
  public:
   // constructors
   constexpr unexpected(const unexpected&) = default;
-  constexpr unexpected(unexpected&&) = default;
+  constexpr unexpected(unexpected&&) noexcept(std::is_nothrow_move_constructible_v<E>) = default;
 
   template <class Err = E _ENABLE_IF(
                 std::is_constructible_v<E, Err> &&
@@ -709,7 +710,8 @@
 
   // assignment
   constexpr unexpected& operator=(const unexpected&) = default;
-  constexpr unexpected& operator=(unexpected&&) = default;
+  constexpr unexpected& operator=(unexpected&&) noexcept(std::is_nothrow_move_assignable_v<E>) =
+      default;
   template<class Err = E>
   constexpr unexpected& operator=(const unexpected<Err>& rhs) {
     val_ = rhs.value();
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 3a02cff..a39245b 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -258,9 +258,9 @@
 
 // A wrapper type that can be implicitly constructed from either int or unique_fd.
 struct borrowed_fd {
-  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}
+  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}  // NOLINT
   template <typename T>
-  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}
+  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}  // NOLINT
 
   int get() const { return fd_; }
 
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 6936cc2..cd9fda3 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -140,13 +140,13 @@
     {"mba_err", 13},
     {"Watchdog", 14},
     {"Panic", 15},
-    {"power_key", 16},  // Mediatek
-    {"power_on", 17},
+    {"power_key", 16},  // aliasReasons to cold,powerkey (Mediatek)
+    {"power_on", 17},   // aliasReasons to cold,powerkey
     {"Reboot", 18},
     {"rtc", 19},
     {"edl", 20},
     {"oem_pon1", 21},
-    {"oem_powerkey", 22},
+    {"oem_powerkey", 22},  // aliasReasons to cold,powerkey
     {"oem_unknown_reset", 23},
     {"srto: HWWDT reset SC", 24},
     {"srto: HWWDT reset platform", 25},
@@ -201,15 +201,15 @@
     {"hard,hw_reset", 72},
     {"shutdown,suspend", 73},    // Suspend to RAM
     {"shutdown,hibernate", 74},  // Suspend to DISK
-    {"power_on_key", 75},
-    {"reboot_by_key", 76},
-    {"wdt_by_pass_pwk", 77},  // Mediatek
-    {"reboot_longkey", 78},
-    {"powerkey", 79},
-    {"usb", 80},               // Mediatek
-    {"wdt", 81},               // Mediatek
-    {"tool_by_pass_pwk", 82},  // Mediatek
-    {"2sec_reboot", 83},       // Mediatek
+    {"power_on_key", 75},        // aliasReasons to cold,powerkey
+    {"reboot_by_key", 76},       // translated to reboot,by_key
+    {"wdt_by_pass_pwk", 77},     // Mediatek
+    {"reboot_longkey", 78},      // translated to reboot,longkey
+    {"powerkey", 79},            // aliasReasons to cold,powerkey
+    {"usb", 80},                 // aliasReasons to cold,charger (Mediatek)
+    {"wdt", 81},                 // Mediatek
+    {"tool_by_pass_pwk", 82},    // aliasReasons to reboot,tool (Mediatek)
+    {"2sec_reboot", 83},         // aliasReasons to cold,rtc,2sec (Mediatek)
     {"reboot,by_key", 84},
     {"reboot,longkey", 85},
     {"reboot,2sec", 86},  // Deprecate in two years, replaced with cold,rtc,2sec
@@ -219,28 +219,28 @@
     {"reboot,rescueparty", 90},
     {"charge", 91},
     {"oem_tz_crash", 92},
-    {"uvlo", 93},  // aliasReasons converts to reboot,undervoltage
+    {"uvlo", 93},  // aliasReasons to reboot,undervoltage
     {"oem_ps_hold", 94},
     {"abnormal_reset", 95},
     {"oemerr_unknown", 96},
     {"reboot_fastboot_mode", 97},
     {"watchdog_apps_bite", 98},
     {"xpu_err", 99},
-    {"power_on_usb", 100},
+    {"power_on_usb", 100},  // aliasReasons to cold,charger
     {"watchdog_rpm", 101},
     {"watchdog_nonsec", 102},
     {"watchdog_apps_bark", 103},
     {"reboot_dmverity_corrupted", 104},
-    {"reboot_smpl", 105},  // aliasReasons converts to reboot,powerloss
+    {"reboot_smpl", 105},  // aliasReasons to reboot,powerloss
     {"watchdog_sdi_apps_reset", 106},
-    {"smpl", 107},  // aliasReasons converts to reboot,powerloss
+    {"smpl", 107},  // aliasReasons to reboot,powerloss
     {"oem_modem_failed_to_powerup", 108},
     {"reboot_normal", 109},
     {"oem_lpass_cfg", 110},
     {"oem_xpu_ns_error", 111},
-    {"power_key_press", 112},
+    {"power_key_press", 112},  // aliasReasons to cold,powerkey
     {"hardware_reset", 113},
-    {"reboot_by_powerkey", 114},
+    {"reboot_by_powerkey", 114},  // aliasReasons to cold,powerkey (is this correct?)
     {"reboot_verity", 115},
     {"oem_rpm_undef_error", 116},
     {"oem_crash_on_the_lk", 117},
@@ -250,7 +250,7 @@
     {"factory_cable", 121},
     {"oem_ar6320_failed_to_powerup", 122},
     {"watchdog_rpm_bite", 123},
-    {"power_on_cable", 124},
+    {"power_on_cable", 124},  // aliasReasons to cold,charger
     {"reboot_unknown", 125},
     {"wireless_charger", 126},
     {"0x776655ff", 127},
@@ -839,12 +839,12 @@
     // following table smaller.
     static const std::vector<std::pair<const std::string, const std::string>> aliasReasons = {
         {"watchdog", "wdog"},
-        {"cold,powerkey", "powerkey|power_key|PowerKey"},
         {"kernel_panic", "panic"},
         {"shutdown,thermal", "thermal"},
         {"warm,s3_wakeup", "s3_wakeup"},
         {"hard,hw_reset", "hw_reset"},
-        {"cold,charger", "usb"},
+        {"cold,charger", "usb|power_on_cable"},
+        {"cold,powerkey", "powerkey|power_key|PowerKey|power_on"},
         {"cold,rtc", "rtc"},
         {"cold,rtc,2sec", "2sec_reboot"},
         {"!warm", "wdt_by_pass_pwk"},  // change flavour of blunt
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a525bd5..ac15ce4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -32,7 +32,6 @@
 #include <unistd.h>
 
 #include <algorithm>
-#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -518,10 +517,166 @@
     return ret;
 }
 
+bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
+    auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
+                     nullptr);
+    if (ret) {
+        PERROR << "__mount(target=" << mount_point
+               << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
+        return false;
+    }
+    return true;
+}
+
+bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
+    auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
+    if (ret) {
+        PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
+        return false;
+    }
+    return true;
+}
+
+struct mount_info {
+    std::string mount_point;
+    bool shared_flag;
+};
+
+std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
+    std::vector<mount_info> info;
+
+    auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (!file) {
+        PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
+        return info;
+    }
+
+    ssize_t len;
+    size_t alloc_len = 0;
+    char* line = nullptr;
+    while ((len = getline(&line, &alloc_len, file.get())) != -1) {
+        /* if the last character is a newline, shorten the string by 1 byte */
+        if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+        }
+
+        static constexpr char delim[] = " \t";
+        char* save_ptr;
+        if (!strtok_r(line, delim, &save_ptr)) {
+            LERROR << "Error parsing mount ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing parent ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount source";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing root";
+            break;
+        }
+
+        char* p;
+        if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
+            LERROR << "Error parsing mount_point";
+            break;
+        }
+        mount_info entry = {p, false};
+
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount_flags";
+            break;
+        }
+
+        while ((p = strtok_r(nullptr, delim, &save_ptr))) {
+            if ((p[0] == '-') && (p[1] == '\0')) break;
+            if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
+        }
+        if (!p) {
+            LERROR << "Error parsing fields";
+            break;
+        }
+        info.emplace_back(std::move(entry));
+    }
+
+    free(line);
+    if (info.empty()) {
+        LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
+    }
+    return info;
+}
+
 bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
     auto options = fs_mgr_get_overlayfs_options(mount_point);
     if (options.empty()) return false;
 
+    auto retval = true;
+    auto save_errno = errno;
+
+    struct move_entry {
+        std::string mount_point;
+        std::string dir;
+        bool shared_flag;
+    };
+    std::vector<move_entry> move;
+    auto parent_private = false;
+    auto parent_made_private = false;
+    auto dev_private = false;
+    auto dev_made_private = false;
+    for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
+        if ((entry.mount_point == mount_point) && !entry.shared_flag) {
+            parent_private = true;
+        }
+        if ((entry.mount_point == "/dev") && !entry.shared_flag) {
+            dev_private = true;
+        }
+
+        if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
+            continue;
+        }
+        if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
+                return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
+            }) != move.end()) {
+            continue;
+        }
+
+        // use as the bound directory in /dev.
+        auto new_context = fs_mgr_get_context(entry.mount_point);
+        if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
+            PERROR << "setfscreatecon " << new_context;
+        }
+        move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
+                                entry.shared_flag};
+        const auto target = mkdtemp(new_entry.dir.data());
+        if (!target) {
+            retval = false;
+            save_errno = errno;
+            PERROR << "temporary directory for MS_BIND";
+            setfscreatecon(nullptr);
+            continue;
+        }
+        setfscreatecon(nullptr);
+
+        if (!parent_private && !parent_made_private) {
+            parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
+        }
+        if (new_entry.shared_flag) {
+            new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
+        }
+        if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
+            retval = false;
+            save_errno = errno;
+            if (new_entry.shared_flag) {
+                fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
+            }
+            continue;
+        }
+        move.emplace_back(std::move(new_entry));
+    }
+
     // hijack __mount() report format to help triage
     auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
     const auto opt_list = android::base::Split(options, ",");
@@ -536,12 +691,38 @@
     auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
                      options.c_str());
     if (ret) {
+        retval = false;
+        save_errno = errno;
         PERROR << report << ret;
-        return false;
     } else {
         LINFO << report << ret;
-        return true;
     }
+
+    // Move submounts back.
+    for (const auto& entry : move) {
+        if (!dev_private && !dev_made_private) {
+            dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
+        }
+
+        if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
+            retval = false;
+            save_errno = errno;
+        } else if (entry.shared_flag &&
+                   !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
+            retval = false;
+            save_errno = errno;
+        }
+        rmdir(entry.dir.c_str());
+    }
+    if (dev_made_private) {
+        fs_mgr_overlayfs_set_shared_mount("/dev", true);
+    }
+    if (parent_made_private) {
+        fs_mgr_overlayfs_set_shared_mount(mount_point, true);
+    }
+
+    errno = save_errno;
+    return retval;
 }
 
 // Mount kScratchMountPoint
diff --git a/init/Android.bp b/init/Android.bp
index 6985677..ba60085 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -107,7 +107,6 @@
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
@@ -159,6 +158,13 @@
     },
 }
 
+phony {
+    name: "init",
+    required: [
+        "init_second_stage",
+    ],
+}
+
 cc_binary {
     name: "init_second_stage",
     recovery_available: true,
@@ -242,18 +248,18 @@
     ],
     whole_static_libs: ["libcap"],
     shared_libs: [
-        "libprotobuf-cpp-lite",
-        "libhidl-gen-utils",
-        "libprocessgroup",
-        "liblog",
         "libcutils",
+        "libhidl-gen-utils",
+        "libjsoncpp",
+        "liblog",
+        "libprocessgroup",
+        "libprotobuf-cpp-lite",
     ],
     srcs: [
         "action.cpp",
         "action_manager.cpp",
         "action_parser.cpp",
         "capabilities.cpp",
-        "descriptors.cpp",
         "epoll.cpp",
         "keychords.cpp",
         "import_parser.cpp",
@@ -286,5 +292,3 @@
         },
     },
 }
-
-subdirs = ["*"]
diff --git a/init/README.md b/init/README.md
index 8179bff..2de76a9 100644
--- a/init/README.md
+++ b/init/README.md
@@ -300,7 +300,8 @@
 
 `socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
 > Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
-  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  User and
+  launched process.  _type_ must be "dgram", "stream" or "seqpacket".  _type_
+  may end with "+passcred" to enable SO_PASSCRED on the socket. User and
   group default to 0.  'seclabel' is the SELinux security context for the
   socket.  It defaults to the service security context, as specified by
   seclabel or computed based on the service executable file security context.
diff --git a/init/action.cpp b/init/action.cpp
index a169591..8cf7645 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -95,7 +95,7 @@
 }
 
 void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
-    commands_.emplace_back(f, false, std::move(args), line);
+    commands_.emplace_back(std::move(f), false, std::move(args), line);
 }
 
 std::size_t Action::NumCommands() const {
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index 985b8ad..541c8f2 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -47,7 +47,7 @@
 void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
     auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
                                            std::map<std::string, std::string>{});
-    action->AddCommand(func, {name}, 0);
+    action->AddCommand(std::move(func), {name}, 0);
 
     event_queue_.emplace(action.get());
     actions_.emplace_back(std::move(action));
diff --git a/init/descriptors.cpp b/init/descriptors.cpp
deleted file mode 100644
index 6265687..0000000
--- a/init/descriptors.cpp
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#include "descriptors.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
-
-#include "util.h"
-
-namespace android {
-namespace init {
-
-DescriptorInfo::DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                               gid_t gid, int perm, const std::string& context)
-        : name_(name), type_(type), uid_(uid), gid_(gid), perm_(perm), context_(context) {
-}
-
-DescriptorInfo::~DescriptorInfo() {
-}
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info) {
-  return os << "  descriptors " << info.name_ << " " << info.type_ << " " << std::oct << info.perm_;
-}
-
-bool DescriptorInfo::operator==(const DescriptorInfo& other) const {
-  return name_ == other.name_ && type_ == other.type_ && key() == other.key();
-}
-
-void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
-  // Create
-  const std::string& contextStr = context_.empty() ? globalContext : context_;
-  int fd = Create(contextStr);
-  if (fd < 0) return;
-
-  // Publish
-  std::string publishedName = key() + name_;
-  std::for_each(publishedName.begin(), publishedName.end(),
-                [] (char& c) { c = isalnum(c) ? c : '_'; });
-
-  std::string val = std::to_string(fd);
-  setenv(publishedName.c_str(), val.c_str(), 1);
-
-  // make sure we don't close on exec
-  fcntl(fd, F_SETFD, 0);
-}
-
-void DescriptorInfo::Clean() const {
-}
-
-SocketInfo::SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-                       gid_t gid, int perm, const std::string& context)
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-void SocketInfo::Clean() const {
-    std::string path = android::base::StringPrintf("%s/%s", ANDROID_SOCKET_DIR, name().c_str());
-    unlink(path.c_str());
-}
-
-int SocketInfo::Create(const std::string& context) const {
-    auto types = android::base::Split(type(), "+");
-    int flags =
-        ((types[0] == "stream" ? SOCK_STREAM : (types[0] == "dgram" ? SOCK_DGRAM : SOCK_SEQPACKET)));
-    bool passcred = types.size() > 1 && types[1] == "passcred";
-    return CreateSocket(name().c_str(), flags, passcred, perm(), uid(), gid(), context.c_str());
-}
-
-const std::string SocketInfo::key() const {
-  return ANDROID_SOCKET_ENV_PREFIX;
-}
-
-FileInfo::FileInfo(const std::string& name, const std::string& type, uid_t uid,
-                   gid_t gid, int perm, const std::string& context)
-        // defaults OK for uid,..., they are ignored for this class.
-        : DescriptorInfo(name, type, uid, gid, perm, context) {
-}
-
-int FileInfo::Create(const std::string&) const {
-  int flags = (type() == "r") ? O_RDONLY :
-              (type() == "w") ? O_WRONLY :
-                                O_RDWR;
-
-  // Make sure we do not block on open (eg: devices can chose to block on
-  // carrier detect).  Our intention is never to delay launch of a service
-  // for such a condition.  The service can perform its own blocking on
-  // carrier detect.
-  android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name().c_str(),
-                                                      flags | O_NONBLOCK)));
-
-  if (fd < 0) {
-    PLOG(ERROR) << "Failed to open file '" << name().c_str() << "'";
-    return -1;
-  }
-
-  // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
-  fcntl(fd, F_SETFL, flags);
-
-  LOG(INFO) << "Opened file '" << name().c_str() << "'"
-            << ", flags " << std::oct << flags << std::dec;
-
-  return fd.release();
-}
-
-const std::string FileInfo::key() const {
-  return ANDROID_FILE_ENV_PREFIX;
-}
-
-}  // namespace init
-}  // namespace android
diff --git a/init/descriptors.h b/init/descriptors.h
deleted file mode 100644
index 3bdddfe..0000000
--- a/init/descriptors.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-
-#ifndef _INIT_DESCRIPTORS_H
-#define _INIT_DESCRIPTORS_H
-
-#include <sys/types.h>
-
-#include <string>
-
-namespace android {
-namespace init {
-
-class DescriptorInfo {
- public:
-  DescriptorInfo(const std::string& name, const std::string& type, uid_t uid,
-                 gid_t gid, int perm, const std::string& context);
-  virtual ~DescriptorInfo();
-
-  friend std::ostream& operator<<(std::ostream& os, const class DescriptorInfo& info);
-  bool operator==(const DescriptorInfo& other) const;
-
-  void CreateAndPublish(const std::string& globalContext) const;
-  virtual void Clean() const;
-
- protected:
-  const std::string& name() const { return name_; }
-  const std::string& type() const { return type_; }
-  uid_t uid() const { return uid_; }
-  gid_t gid() const { return gid_; }
-  int perm() const { return perm_; }
-  const std::string& context() const { return context_; }
-
- private:
-  std::string name_;
-  std::string type_;
-  uid_t uid_;
-  gid_t gid_;
-  int perm_;
-  std::string context_;
-
-  virtual int Create(const std::string& globalContext) const = 0;
-  virtual const std::string key() const = 0;
-};
-
-std::ostream& operator<<(std::ostream& os, const DescriptorInfo& info);
-
-class SocketInfo : public DescriptorInfo {
- public:
-  SocketInfo(const std::string& name, const std::string& type, uid_t uid,
-             gid_t gid, int perm, const std::string& context);
-  void Clean() const override;
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-class FileInfo : public DescriptorInfo {
- public:
-  FileInfo(const std::string& name, const std::string& type, uid_t uid,
-           gid_t gid, int perm, const std::string& context);
- private:
-  virtual int Create(const std::string& context) const override;
-  virtual const std::string key() const override;
-};
-
-}  // namespace init
-}  // namespace android
-
-#endif
diff --git a/init/devices.h b/init/devices.h
index 9d39eaa..442c53f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -84,9 +84,9 @@
     };
 
     Subsystem() {}
-    Subsystem(const std::string& name) : name_(name) {}
-    Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
-        : name_(name), devname_source_(source), dir_name_(dir_name) {}
+    Subsystem(std::string name) : name_(std::move(name)) {}
+    Subsystem(std::string name, DevnameSource source, std::string dir_name)
+        : name_(std::move(name)), devname_source_(source), dir_name_(std::move(dir_name)) {}
 
     // Returns the full path for a uevent of a device that is a member of this subsystem,
     // according to the rules parsed from ueventd.rc
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 3e7c1a8..c408bc1 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
 class DeviceHandlerTester {
   public:
     void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
-                         const std::vector<std::string> expected_links) {
+                         const std::vector<std::string>& expected_links) {
         TemporaryDir fake_sys_root;
         device_handler_.sysfs_mount_point_ = fake_sys_root.path;
 
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 8aa3509..92c2aa5 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <fstream>
 #include <iostream>
 #include <iterator>
 #include <string>
@@ -29,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
+#include <json/json.h>
 
 #include "action.h"
 #include "action_manager.h"
@@ -129,21 +131,33 @@
     return nullptr;
 }
 
-static std::optional<std::set<std::string>> ReadKnownInterfaces(
-        const std::string& known_interfaces_file) {
-    if (known_interfaces_file.empty()) {
-        LOG(WARNING) << "Missing a known interfaces file.";
+static std::optional<android::init::InterfaceInheritanceHierarchyMap>
+ReadInterfaceInheritanceHierarchy(const std::string& interface_inheritance_hierarchy_file) {
+    if (interface_inheritance_hierarchy_file.empty()) {
+        LOG(WARNING) << "Missing an interface inheritance hierarchy file.";
         return {};
     }
 
-    std::string known_interfaces;
-    if (!ReadFileToString(known_interfaces_file, &known_interfaces)) {
-        LOG(ERROR) << "Failed to read known interfaces file '" << known_interfaces_file << "'";
+    Json::Value root;
+    Json::Reader reader;
+    std::ifstream stream(interface_inheritance_hierarchy_file);
+    if (!reader.parse(stream, root)) {
+        LOG(ERROR) << "Failed to read interface inheritance hierarchy file: "
+                   << interface_inheritance_hierarchy_file << "\n"
+                   << reader.getFormattedErrorMessages();
         return {};
     }
 
-    auto interfaces = Split(known_interfaces, " ");
-    return std::set<std::string>(interfaces.begin(), interfaces.end());
+    android::init::InterfaceInheritanceHierarchyMap result;
+    for (const Json::Value& entry : root) {
+        std::set<std::string> inherited_interfaces;
+        for (const Json::Value& intf : entry["inheritedInterfaces"]) {
+            inherited_interfaces.insert(intf.asString());
+        }
+        result[entry["interface"].asString()] = inherited_interfaces;
+    }
+
+    return result;
 }
 
 namespace android {
@@ -169,7 +183,7 @@
     android::base::InitLogging(argv, &android::base::StdioLogger);
     android::base::SetMinimumLogSeverity(android::base::ERROR);
 
-    std::string known_interfaces_file;
+    std::string interface_inheritance_hierarchy_file;
 
     while (true) {
         static const struct option long_options[] = {
@@ -177,7 +191,7 @@
                 {nullptr, 0, nullptr, 0},
         };
 
-        int arg = getopt_long(argc, argv, "p:k:", long_options, nullptr);
+        int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
 
         if (arg == -1) {
             break;
@@ -190,8 +204,8 @@
             case 'p':
                 passwd_files.emplace_back(optarg);
                 break;
-            case 'k':
-                known_interfaces_file = optarg;
+            case 'i':
+                interface_inheritance_hierarchy_file = optarg;
                 break;
             default:
                 std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
@@ -213,8 +227,10 @@
     ServiceList& sl = ServiceList::GetInstance();
     Parser parser;
     parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&sl, nullptr,
-                                                       ReadKnownInterfaces(known_interfaces_file)));
+            "service",
+            std::make_unique<ServiceParser>(
+                    &sl, nullptr,
+                    ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file)));
     parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
     parser.AddSectionParser("import", std::make_unique<HostImportParser>());
 
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d0ca3e7..5f2682b 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -285,7 +285,7 @@
 
 void Keychords::Start(Epoll* epoll, std::function<void(const std::vector<int>&)> handler) {
     epoll_ = epoll;
-    handler_ = handler;
+    handler_ = std::move(handler);
     if (entries_.size()) GeteventOpenDevice();
 }
 
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index b0b63c5..791a019 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -140,11 +140,11 @@
         }
     }
     free(buf);
-    for (auto entry : untouched) {
+    for (auto& entry : untouched) {
         SetMountProperty(entry, false);
         mounts_.erase(entry);
     }
-    for (auto entry : touched) {
+    for (auto& entry : touched) {
         SetMountProperty(entry, true);
         mounts_.emplace(std::move(entry));
     }
diff --git a/init/parser.cpp b/init/parser.cpp
index bbfbdc6..6ab61cb 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -37,7 +37,7 @@
 }
 
 void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
-    line_callbacks_.emplace_back(prefix, callback);
+    line_callbacks_.emplace_back(prefix, std::move(callback));
 }
 
 void Parser::ParseData(const std::string& filename, std::string* data) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 8623c30..3761750 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -994,10 +994,11 @@
 void StartPropertyService(Epoll* epoll) {
     property_set("ro.property_service.version", "2");
 
-    property_set_fd = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
-                                   false, 0666, 0, 0, nullptr);
-    if (property_set_fd == -1) {
-        PLOG(FATAL) << "start_property_service socket creation failed";
+    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                   false, 0666, 0, 0, {})) {
+        property_set_fd = *result;
+    } else {
+        PLOG(FATAL) << "start_property_service socket creation failed: " << result.error();
     }
 
     listen(property_set_fd, 8);
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d9d885c..cb54d34 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -636,11 +636,9 @@
     bool run_fsck = false;
     bool command_invalid = false;
 
-    if (cmd_params.size() > 3) {
-        command_invalid = true;
-    } else if (cmd_params[0] == "shutdown") {
+    if (cmd_params[0] == "shutdown") {
         cmd = ANDROID_RB_POWEROFF;
-        if (cmd_params.size() == 2) {
+        if (cmd_params.size() >= 2) {
             if (cmd_params[1] == "userrequested") {
                 // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
                 // Run fsck once the file system is remounted in read-only mode.
@@ -671,6 +669,13 @@
                                   "bootloader_message: "
                                << err;
                 }
+            } else if (reboot_target == "recovery") {
+                const std::vector<std::string> options = {};
+                std::string err;
+                if (!write_bootloader_message(options, &err)) {
+                    LOG(ERROR) << "Failed to set bootloader message: " << err;
+                    return false;
+                }
             } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
                        reboot_target == "fastboot") {
                 std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
@@ -686,9 +691,9 @@
                 reboot_target = "recovery";
             }
 
-            // If there is an additional parameter, pass it along
-            if ((cmd_params.size() == 3) && cmd_params[2].size()) {
-                reboot_target += "," + cmd_params[2];
+            // If there are additional parameter, pass them along
+            for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {
+                reboot_target += "," + cmd_params[i];
             }
         }
     } else {
diff --git a/init/security.cpp b/init/security.cpp
index 5d87f3c..586d0c7 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -83,7 +83,7 @@
     return {};
 }
 
-static bool SetHighestAvailableOptionValue(std::string path, int min, int max) {
+static bool SetHighestAvailableOptionValue(const std::string& path, int min, int max) {
     std::ifstream inf(path, std::fstream::in);
     if (!inf) {
         LOG(ERROR) << "Cannot open for reading: " << path;
diff --git a/init/service.cpp b/init/service.cpp
index f95b675..47f4db9 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -31,6 +31,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
 
@@ -227,9 +228,11 @@
         KillProcessGroup(SIGKILL);
     }
 
-    // Remove any descriptor resources we may have created.
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  std::bind(&DescriptorInfo::Clean, std::placeholders::_1));
+    // Remove any socket resources we may have created.
+    for (const auto& socket : sockets_) {
+        auto path = ANDROID_SOCKET_DIR "/" + socket.name;
+        unlink(path.c_str());
+    }
 
     for (const auto& f : reap_callbacks_) {
         f(siginfo);
@@ -300,8 +303,12 @@
     LOG(INFO) << "service " << name_;
     LOG(INFO) << "  class '" << Join(classnames_, " ") << "'";
     LOG(INFO) << "  exec " << Join(args_, " ");
-    std::for_each(descriptors_.begin(), descriptors_.end(),
-                  [] (const auto& info) { LOG(INFO) << *info; });
+    for (const auto& socket : sockets_) {
+        LOG(INFO) << "  socket " << socket.name;
+    }
+    for (const auto& file : files_) {
+        LOG(INFO) << "  file " << file.name;
+    }
 }
 
 
@@ -419,8 +426,17 @@
             setenv(key.c_str(), value.c_str(), 1);
         }
 
-        std::for_each(descriptors_.begin(), descriptors_.end(),
-                      std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon));
+        for (const auto& socket : sockets_) {
+            if (auto result = socket.CreateAndPublish(scon); !result) {
+                LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
+            }
+        }
+
+        for (const auto& file : files_) {
+            if (auto result = file.CreateAndPublish(); !result) {
+                LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
+            }
+        }
 
         if (auto result = WritePidToFiles(&writepid_files_); !result) {
             LOG(ERROR) << "failed to write pid to files: " << result.error();
diff --git a/init/service.h b/init/service.h
index cc35a8d..cdf31bb 100644
--- a/init/service.h
+++ b/init/service.h
@@ -31,7 +31,6 @@
 
 #include "action.h"
 #include "capabilities.h"
-#include "descriptors.h"
 #include "keyword_map.h"
 #include "parser.h"
 #include "service_utils.h"
@@ -151,7 +150,8 @@
 
     std::string seclabel_;
 
-    std::vector<std::unique_ptr<DescriptorInfo>> descriptors_;
+    std::vector<SocketDescriptor> sockets_;
+    std::vector<FileDescriptor> files_;
     std::vector<std::pair<std::string, std::string>> environment_vars_;
 
     Action onrestart_;  // Commands to execute on restart.
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index ba35104..0fbbeb8 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -17,6 +17,11 @@
 #include "service_parser.h"
 
 #include <linux/input.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#include <algorithm>
+#include <sstream>
 
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
@@ -25,6 +30,7 @@
 #include <system/thread_defs.h>
 
 #include "rlimit_parser.h"
+#include "service_utils.h"
 #include "util.h"
 
 #if defined(__ANDROID__)
@@ -152,12 +158,6 @@
         return Error() << "Interface name must not be a value name '" << interface_name << "'";
     }
 
-    if (known_interfaces_ && known_interfaces_->count(interface_name) == 0) {
-        return Error() << "Interface is not in the known set of hidl_interfaces: '"
-                       << interface_name << "'. Please ensure the interface is built "
-                       << "by a hidl_interface target.";
-    }
-
     const std::string fullname = interface_name + "/" + instance_name;
 
     for (const auto& svc : *service_list_) {
@@ -347,64 +347,98 @@
     return {};
 }
 
-template <typename T>
-Result<void> ServiceParser::AddDescriptor(std::vector<std::string>&& args) {
-    int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
-    Result<uid_t> uid = 0;
-    Result<gid_t> gid = 0;
-    std::string context = args.size() > 6 ? args[6] : "";
+// name type perm [ uid gid context ]
+Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
+    SocketDescriptor socket;
+    socket.name = std::move(args[1]);
+
+    auto types = Split(args[2], "+");
+    if (types[0] == "stream") {
+        socket.type = SOCK_STREAM;
+    } else if (types[0] == "dgram") {
+        socket.type = SOCK_DGRAM;
+    } else if (types[0] == "seqpacket") {
+        socket.type = SOCK_SEQPACKET;
+    } else {
+        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket', got '" << types[0]
+                       << "' instead.";
+    }
+
+    if (types.size() > 1) {
+        if (types.size() == 2 && types[1] == "passcred") {
+            socket.passcred = true;
+        } else {
+            return Error() << "Only 'passcred' may be used to modify the socket type";
+        }
+    }
+
+    errno = 0;
+    char* end = nullptr;
+    socket.perm = strtol(args[3].c_str(), &end, 8);
+    if (errno != 0) {
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
+    if (end == args[3].c_str() || *end != '\0') {
+        errno = EINVAL;
+        return ErrnoError() << "Unable to parse permissions '" << args[3] << "'";
+    }
 
     if (args.size() > 4) {
-        uid = DecodeUid(args[4]);
+        auto uid = DecodeUid(args[4]);
         if (!uid) {
             return Error() << "Unable to find UID for '" << args[4] << "': " << uid.error();
         }
+        socket.uid = *uid;
     }
 
     if (args.size() > 5) {
-        gid = DecodeUid(args[5]);
+        auto gid = DecodeUid(args[5]);
         if (!gid) {
             return Error() << "Unable to find GID for '" << args[5] << "': " << gid.error();
         }
+        socket.gid = *gid;
     }
 
-    auto descriptor = std::make_unique<T>(args[1], args[2], *uid, *gid, perm, context);
+    socket.context = args.size() > 6 ? args[6] : "";
 
-    auto old = std::find_if(
-            service_->descriptors_.begin(), service_->descriptors_.end(),
-            [&descriptor](const auto& other) { return descriptor.get() == other.get(); });
+    auto old = std::find_if(service_->sockets_.begin(), service_->sockets_.end(),
+                            [&socket](const auto& other) { return socket.name == other.name; });
 
-    if (old != service_->descriptors_.end()) {
-        return Error() << "duplicate descriptor " << args[1] << " " << args[2];
+    if (old != service_->sockets_.end()) {
+        return Error() << "duplicate socket descriptor '" << socket.name << "'";
     }
 
-    service_->descriptors_.emplace_back(std::move(descriptor));
+    service_->sockets_.emplace_back(std::move(socket));
+
     return {};
 }
 
-// name type perm [ uid gid context ]
-Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
-    if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
-        !StartsWith(args[2], "seqpacket")) {
-        return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
-    }
-    return AddDescriptor<SocketInfo>(std::move(args));
-}
-
-// name type perm [ uid gid context ]
+// name type
 Result<void> ServiceParser::ParseFile(std::vector<std::string>&& args) {
     if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
         return Error() << "file type must be 'r', 'w' or 'rw'";
     }
-    std::string expanded;
-    if (!expand_props(args[1], &expanded)) {
+
+    FileDescriptor file;
+    file.type = args[2];
+
+    if (!expand_props(args[1], &file.name)) {
         return Error() << "Could not expand property in file path '" << args[1] << "'";
     }
-    args[1] = std::move(expanded);
-    if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
+    if (file.name[0] != '/' || file.name.find("../") != std::string::npos) {
         return Error() << "file name must not be relative";
     }
-    return AddDescriptor<FileInfo>(std::move(args));
+
+    auto old = std::find_if(service_->files_.begin(), service_->files_.end(),
+                            [&file](const auto& other) { return other.name == file.name; });
+
+    if (old != service_->files_.end()) {
+        return Error() << "duplicate file descriptor '" << file.name << "'";
+    }
+
+    service_->files_.emplace_back(std::move(file));
+
+    return {};
 }
 
 Result<void> ServiceParser::ParseUser(std::vector<std::string>&& args) {
@@ -540,6 +574,37 @@
         return {};
     }
 
+    if (interface_inheritance_hierarchy_) {
+        std::set<std::string> interface_names;
+        for (const std::string& intf : service_->interfaces()) {
+            interface_names.insert(Split(intf, "/")[0]);
+        }
+        std::ostringstream error_stream;
+        for (const std::string& intf : interface_names) {
+            if (interface_inheritance_hierarchy_->count(intf) == 0) {
+                error_stream << "\nInterface is not in the known set of hidl_interfaces: '" << intf
+                             << "'. Please ensure the interface is spelled correctly and built "
+                             << "by a hidl_interface target.";
+                continue;
+            }
+            const std::set<std::string>& required_interfaces =
+                    (*interface_inheritance_hierarchy_)[intf];
+            std::set<std::string> diff;
+            std::set_difference(required_interfaces.begin(), required_interfaces.end(),
+                                interface_names.begin(), interface_names.end(),
+                                std::inserter(diff, diff.begin()));
+            if (!diff.empty()) {
+                error_stream << "\nInterface '" << intf << "' requires its full inheritance "
+                             << "hierarchy to be listed in this init_rc file. Missing "
+                             << "interfaces: [" << base::Join(diff, " ") << "]";
+            }
+        }
+        const std::string& errors = error_stream.str();
+        if (!errors.empty()) {
+            return Error() << errors;
+        }
+    }
+
     Service* old_service = service_list_->FindService(service_->name());
     if (old_service) {
         if (!service_->is_override()) {
diff --git a/init/service_parser.h b/init/service_parser.h
index 5a16768..bca0739 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -26,13 +26,16 @@
 namespace android {
 namespace init {
 
+using InterfaceInheritanceHierarchyMap = std::map<std::string, std::set<std::string>>;
+
 class ServiceParser : public SectionParser {
   public:
-    ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts,
-                  const std::optional<std::set<std::string>>& known_interfaces)
+    ServiceParser(
+            ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+            const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
         : service_list_(service_list),
           subcontexts_(subcontexts),
-          known_interfaces_(known_interfaces),
+          interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
           service_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                               int line) override;
@@ -78,14 +81,11 @@
     Result<void> ParseWritepid(std::vector<std::string>&& args);
     Result<void> ParseUpdatable(std::vector<std::string>&& args);
 
-    template <typename T>
-    Result<void> AddDescriptor(std::vector<std::string>&& args);
-
     bool IsValidName(const std::string& name) const;
 
     ServiceList* service_list_;
     std::vector<Subcontext>* subcontexts_;
-    std::optional<std::set<std::string>> known_interfaces_;
+    std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
     std::unique_ptr<Service> service_;
     std::string filename_;
 };
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 34aa837..836145d 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -27,9 +27,12 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <cutils/android_get_control_file.h>
+#include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
 
 #include "mount_namespace.h"
+#include "util.h"
 
 using android::base::GetProperty;
 using android::base::StartsWith;
@@ -135,8 +138,52 @@
     dup2(fd, 2);
 }
 
+void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
+    std::string published_name = key + name;
+    for (auto& c : published_name) {
+        c = isalnum(c) ? c : '_';
+    }
+
+    std::string val = std::to_string(fd);
+    setenv(published_name.c_str(), val.c_str(), 1);
+}
+
 }  // namespace
 
+Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
+    const auto& socket_context = context.empty() ? global_context : context;
+    auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
+    if (!result) {
+        return result.error();
+    }
+
+    PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
+
+    return {};
+}
+
+Result<void> FileDescriptor::CreateAndPublish() const {
+    int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
+
+    // Make sure we do not block on open (eg: devices can chose to block on carrier detect).  Our
+    // intention is never to delay launch of a service for such a condition.  The service can
+    // perform its own blocking on carrier detect.
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
+
+    if (fd < 0) {
+        return ErrnoError() << "Failed to open file '" << name << "'";
+    }
+
+    // Fixup as we set O_NONBLOCK for open, the intent for fd is to block reads.
+    fcntl(fd, F_SETFL, flags);
+
+    LOG(INFO) << "Opened file '" << name << "', flags " << flags;
+
+    PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
+
+    return {};
+}
+
 Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
     for (const auto& [nstype, path] : info.namespaces_to_enter) {
         if (auto result = EnterNamespace(nstype, path.c_str()); !result) {
diff --git a/init/service_utils.h b/init/service_utils.h
index 365cb29..befce25 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -29,6 +29,25 @@
 namespace android {
 namespace init {
 
+struct SocketDescriptor {
+    std::string name;
+    int type = 0;
+    uid_t uid = 0;
+    gid_t gid = 0;
+    int perm = 0;
+    std::string context;
+    bool passcred = false;
+
+    Result<void> CreateAndPublish(const std::string& global_context) const;
+};
+
+struct FileDescriptor {
+    std::string name;
+    std::string type;
+
+    Result<void> CreateAndPublish() const;
+};
+
 struct NamespaceInfo {
     int flags;
     // Pair of namespace type, path to name.
diff --git a/init/test_function_map.h b/init/test_function_map.h
index 293f1f9..466836c 100644
--- a/init/test_function_map.h
+++ b/init/test_function_map.h
@@ -30,17 +30,17 @@
   public:
     // Helper for argument-less functions
     using BuiltinFunctionNoArgs = std::function<void(void)>;
-    void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
-        Add(name, 0, 0, false, [function](const BuiltinArguments&) {
-            function();
+    void Add(const std::string& name, BuiltinFunctionNoArgs function) {
+        Add(name, 0, 0, false, [f = std::move(function)](const BuiltinArguments&) {
+            f();
             return Result<void>{};
         });
     }
 
     void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters,
-             bool run_in_subcontext, const BuiltinFunction function) {
-        builtin_functions_[name] =
-            make_tuple(min_parameters, max_parameters, make_pair(run_in_subcontext, function));
+             bool run_in_subcontext, BuiltinFunction function) {
+        builtin_functions_[name] = make_tuple(min_parameters, max_parameters,
+                                              make_pair(run_in_subcontext, std::move(function)));
     }
 
   private:
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 3b9de0f..8b2cf62 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -146,7 +146,7 @@
 
 void ColdBoot::RegenerateUevents() {
     uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
-        uevent_queue_.emplace_back(std::move(uevent));
+        uevent_queue_.emplace_back(uevent);
         return ListenerAction::kContinue;
     });
 }
diff --git a/init/util.cpp b/init/util.cpp
index 058a111..8bfb755 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,6 +34,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
@@ -77,32 +78,28 @@
  * daemon. We communicate the file descriptor's value via the environment
  * variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
  */
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon) {
-    if (socketcon) {
-        if (setsockcreatecon(socketcon) == -1) {
-            PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
-            return -1;
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon) {
+    if (!socketcon.empty()) {
+        if (setsockcreatecon(socketcon.c_str()) == -1) {
+            return ErrnoError() << "setsockcreatecon(\"" << socketcon << "\") failed";
         }
     }
 
     android::base::unique_fd fd(socket(PF_UNIX, type, 0));
     if (fd < 0) {
-        PLOG(ERROR) << "Failed to open socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to open socket '" << name << "'";
     }
 
-    if (socketcon) setsockcreatecon(NULL);
+    if (!socketcon.empty()) setsockcreatecon(nullptr);
 
     struct sockaddr_un addr;
     memset(&addr, 0 , sizeof(addr));
     addr.sun_family = AF_UNIX;
-    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
-             name);
+    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR "/%s", name.c_str());
 
     if ((unlink(addr.sun_path) != 0) && (errno != ENOENT)) {
-        PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
-        return -1;
+        return ErrnoError() << "Failed to unlink old socket '" << name << "'";
     }
 
     std::string secontext;
@@ -113,8 +110,7 @@
     if (passcred) {
         int on = 1;
         if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
-            PLOG(ERROR) << "Failed to set SO_PASSCRED '" << name << "'";
-            return -1;
+            return ErrnoError() << "Failed to set SO_PASSCRED '" << name << "'";
         }
     }
 
@@ -125,19 +121,18 @@
         setfscreatecon(nullptr);
     }
 
+    auto guard = android::base::make_scope_guard([&addr] { unlink(addr.sun_path); });
+
     if (ret) {
         errno = savederrno;
-        PLOG(ERROR) << "Failed to bind socket '" << name << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to bind socket '" << name << "'";
     }
 
     if (lchown(addr.sun_path, uid, gid)) {
-        PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to lchown socket '" << addr.sun_path << "'";
     }
     if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
-        PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
-        goto out_unlink;
+        return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
     }
 
     LOG(INFO) << "Created socket '" << addr.sun_path << "'"
@@ -145,11 +140,8 @@
               << ", user " << uid
               << ", group " << gid;
 
+    guard.Disable();
     return fd.release();
-
-out_unlink:
-    unlink(addr.sun_path);
-    return -1;
 }
 
 Result<std::string> ReadFile(const std::string& path) {
diff --git a/init/util.h b/init/util.h
index 1929cb5..6a12fb6 100644
--- a/init/util.h
+++ b/init/util.h
@@ -38,8 +38,8 @@
 
 static const char kColdBootDoneProp[] = "ro.cold_boot_done";
 
-int CreateSocket(const char* name, int type, bool passcred, mode_t perm, uid_t uid, gid_t gid,
-                 const char* socketcon);
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
+                         gid_t gid, const std::string& socketcon);
 
 Result<std::string> ReadFile(const std::string& path);
 Result<void> WriteFile(const std::string& path, const std::string& content);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 63c3793..ae9dab5 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -28,17 +28,10 @@
  *   mediadrm
  * Whose friendly names do not match the #define statements.
  *
- * Additionally, AID_OEM_RESERVED_START and AID_OEM_RESERVED_END
- * can be used to define reserved OEM ranges used for sanity checks
- * during the build process. The rules are, they must end with START/END
- * The proper convention is incrementing a number like so:
- * AID_OEM_RESERVED_START
- * AID_OEM_RESERVED_1_START
- * AID_OEM_RESERVED_2_START
- * ...
- * The same applies to the END.
- * They are not required to be in order, but must not overlap each other and
- * must define a START and END'ing range. START must be smaller than END.
+ * This file must only be used for platform (Google managed, and submitted through AOSP), AIDs.  3rd
+ * party AIDs must be added via config.fs, which will place them in the corresponding partition's
+ * passwd and group files.  There are ranges in this file reserved for AIDs for each 3rd party
+ * partition, from which the system reads passwd and group files.
  */
 
 #ifndef _ANDROID_FILESYSTEM_CONFIG_H_
@@ -141,8 +134,12 @@
 #define AID_CACHE 2001 /* cache access */
 #define AID_DIAG 2002  /* access to diagnostic resources */
 
-/* The range 2900-2999 is reserved for OEM, and must never be
- * used here */
+/* The range 2900-2999 is reserved for the vendor partition */
+/* Note that the two 'OEM' ranges pre-dated the vendor partition, so they take the legacy 'OEM'
+ * name. Additionally, they pre-dated passwd/group files, so there are users and groups named oem_#
+ * created automatically for all values in these ranges.  If there is a user/group in a passwd/group
+ * file corresponding to this range, both the oem_# and user/group names will resolve to the same
+ * value. */
 #define AID_OEM_RESERVED_START 2900
 #define AID_OEM_RESERVED_END 2999
 
@@ -159,10 +156,26 @@
 #define AID_WAKELOCK 3010     /* Allow system wakelock read/write access */
 #define AID_UHID 3011         /* Allow read/write to /dev/uhid node */
 
-/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
+/* The range 5000-5999 is also reserved for vendor partition. */
 #define AID_OEM_RESERVED_2_START 5000
 #define AID_OEM_RESERVED_2_END 5999
 
+/* The range 6000-6499 is reserved for the system partition. */
+#define AID_SYSTEM_RESERVED_START 6000
+#define AID_SYSTEM_RESERVED_END 6499
+
+/* The range 6500-6999 is reserved for the odm partition. */
+#define AID_ODM_RESERVED_START 6500
+#define AID_ODM_RESERVED_END 6999
+
+/* The range 7000-7499 is reserved for the product partition. */
+#define AID_PRODUCT_RESERVED_START 7000
+#define AID_PRODUCT_RESERVED_END 7499
+
+/* The range 7500-7999 is reserved for the system_ext partition. */
+#define AID_SYSTEM_EXT_RESERVED_START 7500
+#define AID_SYSTEM_EXT_RESERVED_END 7999
+
 #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */
 #define AID_MISC 9998      /* access to misc storage */
 #define AID_NOBODY 9999
diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h
index 1fb4151..f782ec5 100644
--- a/libmeminfo/include/meminfo/procmeminfo.h
+++ b/libmeminfo/include/meminfo/procmeminfo.h
@@ -45,6 +45,9 @@
     // vector.
     const std::vector<Vma>& MapsWithPageIdle();
 
+    // Same as Maps() except, do not read the usage stats for each map.
+    const std::vector<Vma>& MapsWithoutUsageStats();
+
     // Collect all 'vma' or 'maps' from /proc/<pid>/smaps and store them in 'maps_'. Returns a
     // constant reference to the vma vector after the collection is done.
     //
@@ -88,7 +91,7 @@
     ~ProcMemInfo() = default;
 
   private:
-    bool ReadMaps(bool get_wss, bool use_pageidle = false);
+    bool ReadMaps(bool get_wss, bool use_pageidle = false, bool get_usage_stats = true);
     bool ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss, bool use_pageidle);
 
     pid_t pid_;
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 5451ca3..4c2be91 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -60,6 +61,103 @@
     EXPECT_FALSE(maps.empty());
 }
 
+TEST(ProcMemInfo, MapsUsageNotEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.Maps();
+    EXPECT_FALSE(maps.empty());
+    uint64_t total_pss = 0;
+    uint64_t total_rss = 0;
+    uint64_t total_uss = 0;
+    for (auto& map : maps) {
+        ASSERT_NE(0, map.usage.vss);
+        total_rss += map.usage.rss;
+        total_pss += map.usage.pss;
+        total_uss += map.usage.uss;
+    }
+
+    // Crude check that stats are actually being read.
+    EXPECT_NE(0, total_rss) << "RSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_pss) << "PSS zero for all maps, that is not possible.";
+    EXPECT_NE(0, total_uss) << "USS zero for all maps, that is not possible.";
+}
+
+TEST(ProcMemInfo, MapsUsageEmpty) {
+    ProcMemInfo proc_mem(pid);
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    EXPECT_FALSE(maps.empty());
+    // Verify that all usage stats are zero in every map.
+    for (auto& map : maps) {
+        ASSERT_EQ(0, map.usage.vss);
+        ASSERT_EQ(0, map.usage.rss);
+        ASSERT_EQ(0, map.usage.pss);
+        ASSERT_EQ(0, map.usage.uss);
+        ASSERT_EQ(0, map.usage.swap);
+        ASSERT_EQ(0, map.usage.swap_pss);
+        ASSERT_EQ(0, map.usage.private_clean);
+        ASSERT_EQ(0, map.usage.private_dirty);
+        ASSERT_EQ(0, map.usage.shared_clean);
+        ASSERT_EQ(0, map.usage.shared_dirty);
+    }
+}
+
+TEST(ProcMemInfo, PageMapPresent) {
+    static constexpr size_t kNumPages = 20;
+    size_t pagesize = getpagesize();
+    void* ptr = mmap(nullptr, pagesize * (kNumPages + 2), PROT_READ | PROT_WRITE,
+                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    ASSERT_NE(MAP_FAILED, ptr);
+
+    // Unmap the first page and the last page so that we guarantee this
+    // map is in a map by itself.
+    ASSERT_EQ(0, munmap(ptr, pagesize));
+    uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + pagesize;
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr + kNumPages * pagesize), pagesize));
+
+    ProcMemInfo proc_mem(getpid());
+    const std::vector<Vma>& maps = proc_mem.MapsWithoutUsageStats();
+    ASSERT_FALSE(maps.empty());
+
+    // Find the vma associated with our previously created map.
+    const Vma* test_vma = nullptr;
+    for (const Vma& vma : maps) {
+        if (vma.start == addr) {
+            test_vma = &vma;
+            break;
+        }
+    }
+    ASSERT_TRUE(test_vma != nullptr) << "Cannot find test map.";
+
+    // Verify that none of the pages are listed as present.
+    std::vector<uint64_t> pagemap;
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                << "Page " << i << " is present and it should not be.";
+    }
+
+    // Make some of the pages present and verify that we see them
+    // as present.
+    uint8_t* data = reinterpret_cast<uint8_t*>(addr);
+    data[0] = 1;
+    data[pagesize * 5] = 1;
+    data[pagesize * 11] = 1;
+
+    ASSERT_TRUE(proc_mem.PageMap(*test_vma, &pagemap));
+    ASSERT_EQ(kNumPages, pagemap.size());
+    for (size_t i = 0; i < pagemap.size(); i++) {
+        if (i == 0 || i == 5 || i == 11) {
+            EXPECT_TRUE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is not present and it should be.";
+        } else {
+            EXPECT_FALSE(android::meminfo::page_present(pagemap[i]))
+                    << "Page " << i << " is present and it should not be.";
+        }
+    }
+
+    ASSERT_EQ(0, munmap(reinterpret_cast<void*>(addr), kNumPages * pagesize));
+}
+
 TEST(ProcMemInfo, WssEmpty) {
     // If we created the object for getting usage,
     // the working set must be empty
diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp
index a8b43c1..6f68ab4 100644
--- a/libmeminfo/procmeminfo.cpp
+++ b/libmeminfo/procmeminfo.cpp
@@ -130,6 +130,14 @@
     return maps_;
 }
 
+const std::vector<Vma>& ProcMemInfo::MapsWithoutUsageStats() {
+    if (maps_.empty() && !ReadMaps(get_wss_, false, false)) {
+        LOG(ERROR) << "Failed to read maps for Process " << pid_;
+    }
+
+    return maps_;
+}
+
 const std::vector<Vma>& ProcMemInfo::Smaps(const std::string& path) {
     if (!maps_.empty()) {
         return maps_;
@@ -213,29 +221,30 @@
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (pagemap_fd < 0) {
+    if (pagemap_fd == -1) {
         PLOG(ERROR) << "Failed to open " << pagemap_file;
         return false;
     }
 
     uint64_t nr_pages = (vma.end - vma.start) / getpagesize();
-    pagemap->reserve(nr_pages);
+    pagemap->resize(nr_pages);
 
-    uint64_t idx = vma.start / getpagesize();
-    uint64_t last = idx + nr_pages;
-    uint64_t val;
-    for (; idx < last; idx++) {
-        if (pread64(pagemap_fd, &val, sizeof(uint64_t), idx * sizeof(uint64_t)) < 0) {
-            PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
-            return false;
-        }
-        pagemap->emplace_back(val);
+    size_t bytes_to_read = sizeof(uint64_t) * nr_pages;
+    off64_t start_addr = (vma.start / getpagesize()) * sizeof(uint64_t);
+    ssize_t bytes_read = pread64(pagemap_fd, pagemap->data(), bytes_to_read, start_addr);
+    if (bytes_read == -1) {
+        PLOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_;
+        return false;
+    } else if (static_cast<size_t>(bytes_read) != bytes_to_read) {
+        LOG(ERROR) << "Failed to read page frames from page map for pid: " << pid_
+                   << ": read bytes " << bytes_read << " expected bytes " << bytes_to_read;
+        return false;
     }
 
     return true;
 }
 
-bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle) {
+bool ProcMemInfo::ReadMaps(bool get_wss, bool use_pageidle, bool get_usage_stats) {
     // Each object reads /proc/<pid>/maps only once. This is done to make sure programs that are
     // running for the lifetime of the system can recycle the objects and don't have to
     // unnecessarily retain and update this object in memory (which can get significantly large).
@@ -256,6 +265,10 @@
         return false;
     }
 
+    if (!get_usage_stats) {
+        return true;
+    }
+
     std::string pagemap_file = ::android::base::StringPrintf("/proc/%d/pagemap", pid_);
     ::android::base::unique_fd pagemap_fd(
             TEMP_FAILURE_RETRY(open(pagemap_file.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index a105474..3a02a8a 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -188,9 +188,6 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
-class TextOutput;
-TextOutput& printWeakPointer(TextOutput& to, const void* val);
-
 // ---------------------------------------------------------------------------
 
 #define COMPARE_WEAK(_op_)                                      \
@@ -459,9 +456,6 @@
     weakref_type*   m_refs;
 };
 
-template <typename T>
-TextOutput& operator<<(TextOutput& to, const wp<T>& val);
-
 #undef COMPARE_WEAK
 
 // ---------------------------------------------------------------------------
@@ -635,12 +629,6 @@
     }
 }
 
-template <typename T>
-inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
-{
-    return printWeakPointer(to, val.unsafe_get());
-}
-
 // ---------------------------------------------------------------------------
 
 // this class just serves as a namespace so TYPE::moveReferences can stay
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index e5b536c..f4544a1 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -3,7 +3,7 @@
 cc_library {
     name: "libvndksupport",
     native_bridge_supported: true,
-    srcs: ["linker.c"],
+    srcs: ["linker.cpp"],
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/libvndksupport/linker.c b/libvndksupport/linker.c
deleted file mode 100644
index 84c2132..0000000
--- a/libvndksupport/linker.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#include "linker.h"
-
-#include <android/dlext.h>
-#include <dlfcn.h>
-
-#define LOG_TAG "vndksupport"
-#include <log/log.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-__attribute__((weak)) extern struct android_namespace_t* android_get_exported_namespace(const char*);
-__attribute__((weak)) extern void* android_dlopen_ext(const char*, int, const android_dlextinfo*);
-
-static const char* namespace_name = NULL;
-
-static struct android_namespace_t* get_vendor_namespace() {
-    const char* namespace_names[] = {"sphal", "default", NULL};
-    static struct android_namespace_t* vendor_namespace = NULL;
-    if (vendor_namespace == NULL) {
-        int name_idx = 0;
-        while (namespace_names[name_idx] != NULL) {
-            if (android_get_exported_namespace != NULL) {
-                vendor_namespace = android_get_exported_namespace(namespace_names[name_idx]);
-            }
-            if (vendor_namespace != NULL) {
-                namespace_name = namespace_names[name_idx];
-                break;
-            }
-            name_idx++;
-        }
-    }
-    return vendor_namespace;
-}
-
-int android_is_in_vendor_process() {
-    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
-    // loaded (sysprop service isn't up for init to know <ver>).
-    if (getpid() == 1) {
-        return 0;
-    }
-    if (android_get_exported_namespace == NULL) {
-        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
-        return 0;
-    }
-
-    // In vendor process, 'vndk' namespace is not visible, whereas in system
-    // process, it is.
-    return android_get_exported_namespace("vndk") == NULL;
-}
-
-void* android_load_sphal_library(const char* name, int flag) {
-    struct android_namespace_t* vendor_namespace = get_vendor_namespace();
-    if (vendor_namespace != NULL) {
-        const android_dlextinfo dlextinfo = {
-            .flags = ANDROID_DLEXT_USE_NAMESPACE, .library_namespace = vendor_namespace,
-        };
-        void* handle = NULL;
-        if (android_dlopen_ext != NULL) {
-            handle = android_dlopen_ext(name, flag, &dlextinfo);
-        }
-        if (!handle) {
-            ALOGE("Could not load %s from %s namespace: %s.", name, namespace_name, dlerror());
-        }
-        return handle;
-    } else {
-        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
-        return dlopen(name, flag);
-    }
-}
-
-int android_unload_sphal_library(void* handle) {
-    return dlclose(handle);
-}
diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp
new file mode 100644
index 0000000..cf0f618
--- /dev/null
+++ b/libvndksupport/linker.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "vndksupport"
+
+#include "linker.h"
+
+#include <android/dlext.h>
+#include <dlfcn.h>
+#include <log/log.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <initializer_list>
+
+__attribute__((weak)) extern "C" android_namespace_t* android_get_exported_namespace(const char*);
+__attribute__((weak)) extern "C" void* android_dlopen_ext(const char*, int,
+                                                          const android_dlextinfo*);
+
+namespace {
+
+struct VendorNamespace {
+    android_namespace_t* ptr = nullptr;
+    const char* name = nullptr;
+};
+
+}  // anonymous namespace
+
+static VendorNamespace get_vendor_namespace() {
+    static VendorNamespace result = ([] {
+        for (const char* name : {"sphal", "default"}) {
+            if (android_get_exported_namespace != nullptr) {
+                if (android_namespace_t* ns = android_get_exported_namespace(name)) {
+                    return VendorNamespace{ns, name};
+                }
+            }
+        }
+        return VendorNamespace{};
+    })();
+    return result;
+}
+
+int android_is_in_vendor_process() {
+    // Special case init, since when init runs, ld.config.<ver>.txt hasn't been
+    // loaded (sysprop service isn't up for init to know <ver>).
+    if (getpid() == 1) {
+        return 0;
+    }
+    if (android_get_exported_namespace == nullptr) {
+        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
+        return 0;
+    }
+
+    // In vendor process, 'vndk' namespace is not visible, whereas in system
+    // process, it is.
+    return android_get_exported_namespace("vndk") == nullptr;
+}
+
+void* android_load_sphal_library(const char* name, int flag) {
+    VendorNamespace vendor_namespace = get_vendor_namespace();
+    if (vendor_namespace.ptr != nullptr) {
+        const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = vendor_namespace.ptr,
+        };
+        void* handle = nullptr;
+        if (android_dlopen_ext != nullptr) {
+            handle = android_dlopen_ext(name, flag, &dlextinfo);
+        }
+        if (!handle) {
+            ALOGE("Could not load %s from %s namespace: %s.", name, vendor_namespace.name,
+                  dlerror());
+        }
+        return handle;
+    } else {
+        ALOGD("Loading %s from current namespace instead of sphal namespace.", name);
+        return dlopen(name, flag);
+    }
+}
+
+int android_unload_sphal_library(void* handle) {
+    return dlclose(handle);
+}
diff --git a/libvndksupport/tests/linker_test.cpp b/libvndksupport/tests/linker_test.cpp
index 7ce27d4..d0c8ef7 100644
--- a/libvndksupport/tests/linker_test.cpp
+++ b/libvndksupport/tests/linker_test.cpp
@@ -21,11 +21,6 @@
 #include <vndksupport/linker.h>
 #include <string>
 
-// Since the test executable will be in /data and ld.config.txt does not
-// configure sphal namespace for executables in /data, the call to
-// android_load_sphal_library will always fallback to the plain dlopen from the
-// default namespace.
-
 // Let's use libEGL_<chipset>.so as a SP-HAL in test
 static std::string find_sphal_lib() {
     const char* path =
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 48140b8..42af751 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -79,6 +79,7 @@
 #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
 #define ZONEINFO_PATH "/proc/zoneinfo"
 #define MEMINFO_PATH "/proc/meminfo"
+#define PROC_STATUS_TGID_FIELD "Tgid:"
 #define LINE_MAX 128
 
 /* Android Logger event logtags (see event.logtags) */
@@ -551,6 +552,49 @@
            (to->tv_nsec - from->tv_nsec) / (long)NS_PER_MS;
 }
 
+static int proc_get_tgid(int pid) {
+    char path[PATH_MAX];
+    char buf[PAGE_SIZE];
+    int fd;
+    ssize_t size;
+    char *pos;
+    int64_t tgid = -1;
+
+    snprintf(path, PATH_MAX, "/proc/%d/status", pid);
+    fd = open(path, O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        return -1;
+    }
+
+    size = read_all(fd, buf, sizeof(buf) - 1);
+    if (size < 0) {
+        goto out;
+    }
+    buf[size] = 0;
+
+    pos = buf;
+    while (true) {
+        pos = strstr(pos, PROC_STATUS_TGID_FIELD);
+        /* Stop if TGID tag not found or found at the line beginning */
+        if (pos == NULL || pos == buf || pos[-1] == '\n') {
+            break;
+        }
+        pos++;
+    }
+
+    if (pos == NULL) {
+        goto out;
+    }
+
+    pos += strlen(PROC_STATUS_TGID_FIELD);
+    while (*pos == ' ') pos++;
+    parse_int64(pos, &tgid);
+
+out:
+    close(fd);
+    return (int)tgid;
+}
+
 static void cmd_procprio(LMKD_CTRL_PACKET packet) {
     struct proc *procp;
     char path[80];
@@ -559,6 +603,7 @@
     struct lmk_procprio params;
     bool is_system_server;
     struct passwd *pwdrec;
+    int tgid;
 
     lmkd_pack_get_procprio(packet, &params);
 
@@ -568,6 +613,14 @@
         return;
     }
 
+    /* Check if registered process is a thread group leader */
+    tgid = proc_get_tgid(params.pid);
+    if (tgid >= 0 && tgid != params.pid) {
+        ALOGE("Attempt to register a task that is not a thread group leader (tid %d, tgid %d)",
+            params.pid, tgid);
+        return;
+    }
+
     /* gid containing AID_READPROC required */
     /* CAP_SYS_RESOURCE required */
     /* CAP_DAC_OVERRIDE required */
@@ -1332,6 +1385,7 @@
 static int kill_one_process(struct proc* procp, int min_oom_score) {
     int pid = procp->pid;
     uid_t uid = procp->uid;
+    int tgid;
     char *taskname;
     int tasksize;
     int r;
@@ -1345,6 +1399,12 @@
     (void)(min_oom_score);
 #endif
 
+    tgid = proc_get_tgid(pid);
+    if (tgid >= 0 && tgid != pid) {
+        ALOGE("Possible pid reuse detected (pid %d, tgid %d)!", pid, tgid);
+        goto out;
+    }
+
     taskname = proc_get_name(pid);
     if (!taskname) {
         goto out;
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 96ffa69..a5bfc41 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,6 +38,13 @@
     # Allow up to 32K FDs per process
     setrlimit nofile 32768 32768
 
+    # Create directory to keep ld.config.txt
+    mkdir /dev/linkerconfig 0755
+
+    # Generate ld.config.txt for early executed processes
+    exec -- /system/bin/linkerconfig --target /dev/linkerconfig/ld.config.txt
+    chmod 444 /dev/linkerconfig/ld.config.txt
+
     start ueventd
 
     # Run apexd-bootstrap so that APEXes that provide critical libraries