Merge "ld-config: Add HIDL memory libs to VNDK-SP" into oc-dev
diff --git a/init/devices.cpp b/init/devices.cpp
index 6f86662..39571ac 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -19,7 +19,6 @@
 #include <fcntl.h>
 #include <fnmatch.h>
 #include <libgen.h>
-#include <poll.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -47,7 +46,6 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
-#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/list.h>
 #include <cutils/uevent.h>
@@ -81,8 +79,16 @@
     struct listnode plist;
 };
 
+struct platform_node {
+    char *name;
+    char *path;
+    int path_len;
+    struct listnode list;
+};
+
 static list_declare(sys_perms);
 static list_declare(dev_perms);
+static list_declare(platform_names);
 
 int add_dev_perms(const char *name, const char *attr,
                   mode_t perm, unsigned int uid, unsigned int gid,
@@ -280,37 +286,77 @@
     }
 }
 
-// Given a path that may start with a platform device, find the parent platform device by finding a
-// parent directory with a 'subsystem' symlink that points to the platform bus.
-// If it doesn't start with a platform device, return false
-bool FindPlatformDevice(std::string path, std::string* platform_device_path) {
-    platform_device_path->clear();
+static void add_platform_device(const char *path)
+{
+    int path_len = strlen(path);
+    struct platform_node *bus;
+    const char *name = path;
 
-    static const std::string kSysfsMountPoint = "/sys";
-
-    // Uevents don't contain the mount point, so we need to add it here.
-    path.insert(0, kSysfsMountPoint);
-
-    std::string directory = android::base::Dirname(path);
-
-    while (directory != "/" && directory != ".") {
-        std::string subsystem_link_path;
-        if (android::base::Realpath(directory + "/subsystem", &subsystem_link_path) &&
-            subsystem_link_path == kSysfsMountPoint + "/bus/platform") {
-            // We need to remove the mount point that we added above before returning.
-            directory.erase(0, kSysfsMountPoint.size());
-            *platform_device_path = directory;
-            return true;
-        }
-
-        auto last_slash = path.rfind('/');
-        if (last_slash == std::string::npos) return false;
-
-        path.erase(last_slash);
-        directory = android::base::Dirname(path);
+    if (!strncmp(path, "/devices/", 9)) {
+        name += 9;
+        if (!strncmp(name, "platform/", 9))
+            name += 9;
     }
 
-    return false;
+    LOG(VERBOSE) << "adding platform device " << name << " (" << path << ")";
+
+    bus = (platform_node*) calloc(1, sizeof(struct platform_node));
+    bus->path = strdup(path);
+    bus->path_len = path_len;
+    bus->name = bus->path + (name - path);
+    list_add_tail(&platform_names, &bus->list);
+}
+
+/*
+ * given a path that may start with a platform device, find the length of the
+ * platform device prefix.  If it doesn't start with a platform device, return
+ * 0.
+ */
+static struct platform_node *find_platform_device(const char *path)
+{
+    int path_len = strlen(path);
+    struct listnode *node;
+    struct platform_node *bus;
+
+    list_for_each_reverse(node, &platform_names) {
+        bus = node_to_item(node, struct platform_node, list);
+        if ((bus->path_len < path_len) &&
+                (path[bus->path_len] == '/') &&
+                !strncmp(path, bus->path, bus->path_len))
+            return bus;
+    }
+
+    return NULL;
+}
+
+static void remove_platform_device(const char *path)
+{
+    struct listnode *node;
+    struct platform_node *bus;
+
+    list_for_each_reverse(node, &platform_names) {
+        bus = node_to_item(node, struct platform_node, list);
+        if (!strcmp(path, bus->path)) {
+            LOG(INFO) << "removing platform device " << bus->name;
+            free(bus->path);
+            list_remove(node);
+            free(bus);
+            return;
+        }
+    }
+}
+
+static void destroy_platform_devices() {
+    struct listnode* node;
+    struct listnode* n;
+    struct platform_node* bus;
+
+    list_for_each_safe(node, n, &platform_names) {
+        list_remove(node);
+        bus = node_to_item(node, struct platform_node, list);
+        free(bus->path);
+        free(bus);
+    }
 }
 
 /* Given a path that may start with a PCI device, populate the supplied buffer
@@ -434,9 +480,11 @@
     char **links;
     int link_num = 0;
     int width;
+    struct platform_node *pdev;
 
-    std::string platform_device;
-    if (!FindPlatformDevice(uevent->path, &platform_device)) return nullptr;
+    pdev = find_platform_device(uevent->path);
+    if (!pdev)
+        return NULL;
 
     links = (char**) malloc(sizeof(char *) * 2);
     if (!links)
@@ -444,7 +492,7 @@
     memset(links, 0, sizeof(char *) * 2);
 
     /* skip "/devices/platform/<driver>" */
-    parent = strchr(uevent->path + platform_device.size(), '/');
+    parent = strchr(uevent->path + pdev->path_len, '/');
     if (!parent)
         goto err;
 
@@ -479,6 +527,8 @@
 }
 
 char** get_block_device_symlinks(struct uevent* uevent) {
+    const char *device;
+    struct platform_node *pdev;
     const char *slash;
     const char *type;
     char buf[256];
@@ -486,18 +536,9 @@
     int link_num = 0;
     char *p;
 
-    std::string device;
-    if (FindPlatformDevice(uevent->path, &device)) {
-        // Skip /devices/platform or /devices/ if present
-        static const std::string devices_platform_prefix = "/devices/platform/";
-        static const std::string devices_prefix = "/devices/";
-
-        if (android::base::StartsWith(device, devices_platform_prefix.c_str())) {
-            device = device.substr(devices_platform_prefix.length());
-        } else if (android::base::StartsWith(device, devices_prefix.c_str())) {
-            device = device.substr(devices_prefix.length());
-        }
-
+    pdev = find_platform_device(uevent->path);
+    if (pdev) {
+        device = pdev->name;
         type = "platform";
     } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) {
         device = buf;
@@ -516,7 +557,7 @@
 
     LOG(VERBOSE) << "found " << type << " device " << device;
 
-    snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device.c_str());
+    snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
 
     if (uevent->partition_name) {
         p = strdup(uevent->partition_name);
@@ -594,6 +635,16 @@
     }
 }
 
+static void handle_platform_device_event(struct uevent *uevent)
+{
+    const char *path = uevent->path;
+
+    if (!strcmp(uevent->action, "add"))
+        add_platform_device(path);
+    else if (!strcmp(uevent->action, "remove"))
+        remove_platform_device(path);
+}
+
 static const char *parse_device_name(struct uevent *uevent, unsigned int len)
 {
     const char *name;
@@ -773,6 +824,8 @@
 
     if (!strncmp(uevent->subsystem, "block", 5)) {
         handle_block_device_event(uevent);
+    } else if (!strncmp(uevent->subsystem, "platform", 8)) {
+        handle_platform_device_event(uevent);
     } else {
         handle_generic_device_event(uevent);
     }
@@ -1025,41 +1078,11 @@
 }
 
 void device_close() {
+    destroy_platform_devices();
     device_fd.reset();
     selinux_status_close();
 }
 
-void device_poll(const coldboot_callback& callback,
-                 const std::optional<std::chrono::milliseconds> relative_timeout) {
-    using namespace std::chrono;
-
-    pollfd ufd;
-    ufd.events = POLLIN;
-    ufd.fd = device_fd;
-
-    auto start_time = steady_clock::now();
-
-    while (true) {
-        ufd.revents = 0;
-
-        int timeout_ms = -1;
-        if (relative_timeout) {
-            auto now = steady_clock::now();
-            auto time_elapsed = duration_cast<milliseconds>(now - start_time);
-            if (time_elapsed > *relative_timeout) return;
-
-            auto remaining_timeout = *relative_timeout - time_elapsed;
-            timeout_ms = remaining_timeout.count();
-        }
-
-        int nr = poll(&ufd, 1, timeout_ms);
-        if (nr == 0) return;
-        if (nr < 0) {
-            continue;
-        }
-        if (ufd.revents & POLLIN) {
-            auto ret = handle_device_fd(callback);
-            if (should_stop_coldboot(ret)) return;
-        }
-    }
+int get_device_fd() {
+    return device_fd;
 }
diff --git a/init/devices.h b/init/devices.h
index 62aef2e..3f2cde4 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,11 +17,8 @@
 #ifndef _INIT_DEVICES_H
 #define _INIT_DEVICES_H
 
-#include <sys/stat.h>
-
-#include <chrono>
 #include <functional>
-#include <optional>
+#include <sys/stat.h>
 
 enum coldboot_action_t {
     // coldboot continues without creating the device for the uevent
@@ -56,10 +53,8 @@
                          mode_t perm, unsigned int uid,
                          unsigned int gid, unsigned short prefix,
                          unsigned short wildcard);
+int get_device_fd();
 
 char** get_block_device_symlinks(struct uevent* uevent);
 
-void device_poll(const coldboot_callback& callback = nullptr,
-                 const std::optional<std::chrono::milliseconds> relative_timeout = {});
-
 #endif	/* _INIT_DEVICES_H */
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 9425027..bcc8d1b 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -19,7 +19,6 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#include <chrono>
 #include <memory>
 #include <set>
 #include <string>
@@ -34,8 +33,6 @@
 #include "fs_mgr_avb.h"
 #include "util.h"
 
-using namespace std::chrono_literals;
-
 // Class Declarations
 // ------------------
 class FirstStageMount {
@@ -50,8 +47,8 @@
     bool InitDevices();
 
   protected:
-    bool InitRequiredDevices();
-    bool InitVerityDevice(const std::string& verity_device);
+    void InitRequiredDevices();
+    void InitVerityDevice(const std::string& verity_device);
     bool MountPartitions();
 
     virtual coldboot_action_t ColdbootCallback(uevent* uevent);
@@ -142,56 +139,50 @@
     return true;
 }
 
-bool FirstStageMount::InitDevices() { return GetRequiredDevices() && InitRequiredDevices(); }
+bool FirstStageMount::InitDevices() {
+    if (!GetRequiredDevices()) return false;
+
+    InitRequiredDevices();
+
+    // InitRequiredDevices() will remove found partitions from required_devices_partition_names_.
+    // So if it isn't empty here, it means some partitions are not found.
+    if (!required_devices_partition_names_.empty()) {
+        LOG(ERROR) << __FUNCTION__ << "(): partition(s) not found: "
+                   << android::base::Join(required_devices_partition_names_, ", ");
+        return false;
+    } else {
+        return true;
+    }
+}
 
 // Creates devices with uevent->partition_name matching one in the member variable
 // required_devices_partition_names_. Found partitions will then be removed from it
 // for the subsequent member function to check which devices are NOT created.
-bool FirstStageMount::InitRequiredDevices() {
+void FirstStageMount::InitRequiredDevices() {
     if (required_devices_partition_names_.empty()) {
-        return true;
+        return;
     }
 
     if (need_dm_verity_) {
         const std::string dm_path = "/devices/virtual/misc/device-mapper";
-        bool found = false;
-        auto dm_callback = [&dm_path, &found](uevent* uevent) -> coldboot_action_t {
-            if (uevent->path && uevent->path == dm_path) {
-                found = true;
-                return COLDBOOT_STOP;
-            }
+        device_init(("/sys" + dm_path).c_str(), [&dm_path](uevent* uevent) -> coldboot_action_t {
+            if (uevent->path && uevent->path == dm_path) return COLDBOOT_STOP;
             return COLDBOOT_CONTINUE;  // dm_path not found, continue to find it.
-        };
-        device_init(("/sys" + dm_path).c_str(), dm_callback);
-        if (!found) {
-            device_poll(dm_callback, 10s);
-        }
-        if (!found) {
-            LOG(ERROR) << "device-mapper device not found";
-            return false;
-        }
+        });
     }
 
-    auto uevent_callback = [this](uevent* uevent) -> coldboot_action_t {
-        return ColdbootCallback(uevent);
-    };
-
-    device_init(nullptr, uevent_callback);
-    if (!required_devices_partition_names_.empty()) {
-        device_poll(uevent_callback, 10s);
-    }
-
-    if (!required_devices_partition_names_.empty()) {
-        LOG(ERROR) << __PRETTY_FUNCTION__ << ": partition(s) not found: "
-                   << android::base::Join(required_devices_partition_names_, ", ");
-        return false;
-    }
+    device_init(nullptr,
+                [this](uevent* uevent) -> coldboot_action_t { return ColdbootCallback(uevent); });
 
     device_close();
-    return true;
 }
 
 coldboot_action_t FirstStageMount::ColdbootCallback(uevent* uevent) {
+    // We need platform devices to create symlinks.
+    if (!strncmp(uevent->subsystem, "platform", 8)) {
+        return COLDBOOT_CREATE;
+    }
+
     // Ignores everything that is not a block device.
     if (strncmp(uevent->subsystem, "block", 5)) {
         return COLDBOOT_CONTINUE;
@@ -217,30 +208,18 @@
 }
 
 // Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
-bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
+void FirstStageMount::InitVerityDevice(const std::string& verity_device) {
     const std::string device_name(basename(verity_device.c_str()));
     const std::string syspath = "/sys/block/" + device_name;
-    bool found = false;
 
-    auto verity_callback = [&](uevent* uevent) -> coldboot_action_t {
+    device_init(syspath.c_str(), [&](uevent* uevent) -> coldboot_action_t {
         if (uevent->device_name && uevent->device_name == device_name) {
             LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
-            found = true;
             return COLDBOOT_STOP;
         }
         return COLDBOOT_CONTINUE;
-    };
-
-    device_init(syspath.c_str(), verity_callback);
-    if (!found) {
-        device_poll(verity_callback, 10s);
-    }
-    if (!found) {
-        LOG(ERROR) << "dm-verity device not found";
-        return false;
-    }
+    });
     device_close();
-    return true;
 }
 
 bool FirstStageMount::MountPartitions() {
@@ -306,7 +285,7 @@
         } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
             // The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
             // Needs to create it because ueventd isn't started in init first stage.
-            return InitVerityDevice(fstab_rec->blk_device);
+            InitVerityDevice(fstab_rec->blk_device);
         } else {
             return false;
         }
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index d0b7b8e..f27be64 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -17,6 +17,7 @@
 #include <ctype.h>
 #include <fcntl.h>
 #include <grp.h>
+#include <poll.h>
 #include <pwd.h>
 #include <signal.h>
 #include <stdio.h>
@@ -75,7 +76,20 @@
 
     device_init();
 
-    device_poll();
+    pollfd ufd;
+    ufd.events = POLLIN;
+    ufd.fd = get_device_fd();
+
+    while (true) {
+        ufd.revents = 0;
+        int nr = poll(&ufd, 1, -1);
+        if (nr <= 0) {
+            continue;
+        }
+        if (ufd.revents & POLLIN) {
+            handle_device_fd();
+        }
+    }
 
     return 0;
 }