Merge "ld-config: Add HIDL memory libs to VNDK-SP" into oc-dev-plus-aosp
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index d26530b..676ee41 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -116,6 +116,10 @@
         { "Over voltage", BATTERY_HEALTH_OVER_VOLTAGE },
         { "Unspecified failure", BATTERY_HEALTH_UNSPECIFIED_FAILURE },
         { "Cold", BATTERY_HEALTH_COLD },
+        // battery health values from JEITA spec
+        { "Warm", BATTERY_HEALTH_GOOD },
+        { "Cool", BATTERY_HEALTH_GOOD },
+        { "Hot", BATTERY_HEALTH_OVERHEAT },
         { NULL, 0 },
     };
 
diff --git a/init/devices.cpp b/init/devices.cpp
index 2943fb7..c52d8f8 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -147,34 +147,21 @@
     }
 }
 
-// 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 DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const {
-    platform_device_path->clear();
-
-    // Uevents don't contain the mount point, so we need to add it here.
-    path.insert(0, sysfs_mount_point_);
-
-    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 == sysfs_mount_point_ + "/bus/platform") {
-            // We need to remove the mount point that we added above before returning.
-            directory.erase(0, sysfs_mount_point_.size());
-            *platform_device_path = directory;
+// 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 false
+bool PlatformDeviceList::Find(const std::string& path, std::string* out_path) const {
+    out_path->clear();
+    // platform_devices is searched backwards, since parents are added before their children,
+    // and we want to match as deep of a child as we can.
+    for (auto it = platform_devices_.crbegin(); it != platform_devices_.crend(); ++it) {
+        auto platform_device_path_length = it->length();
+        if (platform_device_path_length < path.length() &&
+            path[platform_device_path_length] == '/' &&
+            android::base::StartsWith(path, it->c_str())) {
+            *out_path = *it;
             return true;
         }
-
-        auto last_slash = path.rfind('/');
-        if (last_slash == std::string::npos) return false;
-
-        path.erase(last_slash);
-        directory = android::base::Dirname(path);
     }
-
     return false;
 }
 
@@ -271,7 +258,7 @@
 
 std::vector<std::string> DeviceHandler::GetCharacterDeviceSymlinks(const Uevent& uevent) const {
     std::string parent_device;
-    if (!FindPlatformDevice(uevent.path, &parent_device)) return {};
+    if (!platform_devices_.Find(uevent.path, &parent_device)) return {};
 
     // skip path to the parent driver
     std::string path = uevent.path.substr(parent_device.length());
@@ -329,7 +316,7 @@
     std::string device;
     std::string type;
 
-    if (FindPlatformDevice(uevent.path, &device)) {
+    if (platform_devices_.Find(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/";
@@ -401,6 +388,14 @@
     }
 }
 
+void DeviceHandler::HandlePlatformDeviceEvent(const Uevent& uevent) {
+    if (uevent.action == "add") {
+        platform_devices_.Add(uevent.path);
+    } else if (uevent.action == "remove") {
+        platform_devices_.Remove(uevent.path);
+    }
+}
+
 void DeviceHandler::HandleBlockDeviceEvent(const Uevent& uevent) const {
     // if it's not a /dev device, nothing to do
     if (uevent.major < 0 || uevent.minor < 0) return;
@@ -463,6 +458,8 @@
 
     if (uevent.subsystem == "block") {
         HandleBlockDeviceEvent(uevent);
+    } else if (uevent.subsystem == "platform") {
+        HandlePlatformDeviceEvent(uevent);
     } else {
         HandleGenericDeviceEvent(uevent);
     }
@@ -475,8 +472,7 @@
       sysfs_permissions_(std::move(sysfs_permissions)),
       subsystems_(std::move(subsystems)),
       sehandle_(selinux_android_file_context_handle()),
-      skip_restorecon_(skip_restorecon),
-      sysfs_mount_point_("/sys") {}
+      skip_restorecon_(skip_restorecon) {}
 
 DeviceHandler::DeviceHandler()
     : DeviceHandler(std::vector<Permissions>{}, std::vector<SysfsPermissions>{},
diff --git a/init/devices.h b/init/devices.h
index 362c38c..09a0ce3 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -93,6 +93,20 @@
     DevnameSource devname_source_;
 };
 
+class PlatformDeviceList {
+  public:
+    void Add(const std::string& path) { platform_devices_.emplace_back(path); }
+    void Remove(const std::string& path) {
+        auto it = std::find(platform_devices_.begin(), platform_devices_.end(), path);
+        if (it != platform_devices_.end()) platform_devices_.erase(it);
+    }
+    bool Find(const std::string& path, std::string* out_path) const;
+    auto size() const { return platform_devices_.size(); }
+
+  private:
+    std::vector<std::string> platform_devices_;
+};
+
 class DeviceHandler {
   public:
     friend class DeviceHandlerTester;
@@ -105,11 +119,16 @@
 
     void HandleDeviceEvent(const Uevent& uevent);
 
+    void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
+
+    void HandlePlatformDeviceEvent(const Uevent& uevent);
+    void HandleBlockDeviceEvent(const Uevent& uevent) const;
+    void HandleGenericDeviceEvent(const Uevent& uevent) const;
+
     std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
     void set_skip_restorecon(bool value) { skip_restorecon_ = value; }
 
   private:
-    bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
     std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
         const std::string& path, const std::vector<std::string>& links) const;
     void MakeDevice(const std::string& path, int block, int major, int minor,
@@ -117,17 +136,13 @@
     std::vector<std::string> GetCharacterDeviceSymlinks(const Uevent& uevent) const;
     void HandleDevice(const std::string& action, const std::string& devpath, int block, int major,
                       int minor, const std::vector<std::string>& links) const;
-    void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
-
-    void HandleBlockDeviceEvent(const Uevent& uevent) const;
-    void HandleGenericDeviceEvent(const Uevent& uevent) const;
 
     std::vector<Permissions> dev_permissions_;
     std::vector<SysfsPermissions> sysfs_permissions_;
     std::vector<Subsystem> subsystems_;
+    PlatformDeviceList platform_devices_;
     selabel_handle* sehandle_;
     bool skip_restorecon_;
-    std::string sysfs_mount_point_;
 };
 
 // Exposed for testing
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index e1e4e49..41b101b 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -16,29 +16,33 @@
 
 #include "devices.h"
 
+#include <string>
+#include <vector>
+
 #include <android-base/scopeguard.h>
-#include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
-#include "util.h"
-
-using namespace std::string_literals;
-
 class DeviceHandlerTester {
   public:
-    void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
+    void AddPlatformDevice(const std::string& path) {
+        Uevent uevent = {
+            .action = "add", .subsystem = "platform", .path = path,
+        };
+        device_handler_.HandlePlatformDeviceEvent(uevent);
+    }
+
+    void RemovePlatformDevice(const std::string& path) {
+        Uevent uevent = {
+            .action = "remove", .subsystem = "platform", .path = path,
+        };
+        device_handler_.HandlePlatformDeviceEvent(uevent);
+    }
+
+    void TestGetSymlinks(const std::string& platform_device_name, const Uevent& uevent,
                          const std::vector<std::string> expected_links, bool block) {
-        TemporaryDir fake_sys_root;
-        device_handler_.sysfs_mount_point_ = fake_sys_root.path;
-
-        std::string platform_device_dir = fake_sys_root.path + platform_device;
-        mkdir_recursive(platform_device_dir, 0777, nullptr);
-
-        std::string platform_bus = fake_sys_root.path + "/bus/platform"s;
-        mkdir_recursive(platform_bus, 0777, nullptr);
-        symlink(platform_bus.c_str(), (platform_device_dir + "/subsystem").c_str());
-
-        mkdir_recursive(android::base::Dirname(fake_sys_root.path + uevent.path), 0777, nullptr);
+        AddPlatformDevice(platform_device_name);
+        auto platform_device_remover = android::base::make_scope_guard(
+            [this, &platform_device_name]() { RemovePlatformDevice(platform_device_name); });
 
         std::vector<std::string> result;
         if (block) {
@@ -61,6 +65,30 @@
     DeviceHandler device_handler_;
 };
 
+TEST(device_handler, PlatformDeviceList) {
+    PlatformDeviceList platform_device_list;
+
+    platform_device_list.Add("/devices/platform/some_device_name");
+    platform_device_list.Add("/devices/platform/some_device_name/longer");
+    platform_device_list.Add("/devices/platform/other_device_name");
+    EXPECT_EQ(3U, platform_device_list.size());
+
+    std::string out_path;
+    EXPECT_FALSE(platform_device_list.Find("/devices/platform/not_found", &out_path));
+    EXPECT_EQ("", out_path);
+
+    EXPECT_FALSE(platform_device_list.Find("/devices/platform/some_device_name_with_same_prefix",
+                                           &out_path));
+
+    EXPECT_TRUE(platform_device_list.Find("/devices/platform/some_device_name/longer/longer_child",
+                                          &out_path));
+    EXPECT_EQ("/devices/platform/some_device_name/longer", out_path);
+
+    EXPECT_TRUE(
+        platform_device_list.Find("/devices/platform/some_device_name/other_child", &out_path));
+    EXPECT_EQ("/devices/platform/some_device_name", out_path);
+}
+
 TEST(device_handler, get_character_device_symlinks_success) {
     const char* platform_device = "/devices/platform/some_device_name";
     Uevent uevent = {
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 8433056..0f2b1f3 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>
@@ -36,8 +35,6 @@
 #include "uevent_listener.h"
 #include "util.h"
 
-using namespace std::chrono_literals;
-
 // Class Declarations
 // ------------------
 class FirstStageMount {
@@ -52,11 +49,11 @@
     bool InitDevices();
 
   protected:
-    bool InitRequiredDevices();
-    bool InitVerityDevice(const std::string& verity_device);
+    void InitRequiredDevices();
+    void InitVerityDevice(const std::string& verity_device);
     bool MountPartitions();
 
-    virtual ListenerAction UeventCallback(const Uevent& uevent);
+    virtual RegenerationAction UeventCallback(const Uevent& uevent);
 
     // Pure virtual functions.
     virtual bool GetRequiredDevices() = 0;
@@ -89,7 +86,7 @@
     ~FirstStageMountVBootV2() override = default;
 
   protected:
-    ListenerAction UeventCallback(const Uevent& uevent) override;
+    RegenerationAction UeventCallback(const Uevent& uevent) override;
     bool GetRequiredDevices() override;
     bool SetUpDmVerity(fstab_rec* fstab_rec) override;
     bool InitAvbHandle();
@@ -144,60 +141,55 @@
 }
 
 bool FirstStageMount::InitDevices() {
-    return GetRequiredDevices() && InitRequiredDevices();
+    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 = [this, &dm_path, &found](const Uevent& uevent) {
-            if (uevent.path == dm_path) {
-                device_handler_.HandleDeviceEvent(uevent);
-                found = true;
-                return ListenerAction::kStop;
-            }
-            return ListenerAction::kContinue;
-        };
-        uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
-        if (!found) {
-            uevent_listener_.Poll(dm_callback, 10s);
-        }
-        if (!found) {
-            LOG(ERROR) << "device-mapper device not found";
-            return false;
-        }
+        uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path,
+                                                  [this, &dm_path](const Uevent& uevent) {
+                                                      if (uevent.path == dm_path) {
+                                                          device_handler_.HandleDeviceEvent(uevent);
+                                                          return RegenerationAction::kStop;
+                                                      }
+                                                      return RegenerationAction::kContinue;
+                                                  });
     }
 
-    auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
-    uevent_listener_.RegenerateUevents(uevent_callback);
-
-    // UeventCallback() 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()) {
-        uevent_listener_.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;
-    }
-
-    return true;
+    uevent_listener_.RegenerateUevents(
+        [this](const Uevent& uevent) { return UeventCallback(uevent); });
 }
 
-ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
+RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
+    // We need platform devices to create symlinks.
+    if (uevent.subsystem == "platform") {
+        device_handler_.HandleDeviceEvent(uevent);
+        return RegenerationAction::kContinue;
+    }
+
     // Ignores everything that is not a block device.
     if (uevent.subsystem != "block") {
-        return ListenerAction::kContinue;
+        return RegenerationAction::kContinue;
     }
 
     if (!uevent.partition_name.empty()) {
@@ -206,46 +198,34 @@
         // suffix when A/B is used.
         auto iter = required_devices_partition_names_.find(uevent.partition_name);
         if (iter != required_devices_partition_names_.end()) {
-            LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+            LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
             required_devices_partition_names_.erase(iter);
             device_handler_.HandleDeviceEvent(uevent);
             if (required_devices_partition_names_.empty()) {
-                return ListenerAction::kStop;
+                return RegenerationAction::kStop;
             } else {
-                return ListenerAction::kContinue;
+                return RegenerationAction::kContinue;
             }
         }
     }
     // Not found a partition or find an unneeded partition, continue to find others.
-    return ListenerAction::kContinue;
+    return RegenerationAction::kContinue;
 }
 
 // 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 = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
-        if (uevent.device_name == device_name) {
-            LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
-            device_handler_.HandleDeviceEvent(uevent);
-            found = true;
-            return ListenerAction::kStop;
-        }
-        return ListenerAction::kContinue;
-    };
-
-    uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
-    if (!found) {
-        uevent_listener_.Poll(verity_callback, 10s);
-    }
-    if (!found) {
-        LOG(ERROR) << "dm-verity device not found";
-        return false;
-    }
-
-    return true;
+    uevent_listener_.RegenerateUeventsForPath(
+        syspath, [&device_name, &verity_device, this](const Uevent& uevent) {
+            if (uevent.device_name == device_name) {
+                LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
+                device_handler_.HandleDeviceEvent(uevent);
+                return RegenerationAction::kStop;
+            }
+            return RegenerationAction::kContinue;
+        });
 }
 
 bool FirstStageMount::MountPartitions() {
@@ -311,7 +291,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;
         }
@@ -371,7 +351,7 @@
     return true;
 }
 
-ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
+RegenerationAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
     // Check if this uevent corresponds to one of the required partitions and store its symlinks if
     // so, in order to create FsManagerAvbHandle later.
     // Note that the parent callback removes partitions from the list of required partitions
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index c748984..27c5d23 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -121,8 +121,8 @@
 // make sure we don't overrun the socket's buffer.
 //
 
-ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
-                                                       const ListenerCallback& callback) const {
+RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
+                                                           RegenerateCallback callback) const {
     int dfd = dirfd(d);
 
     int fd = openat(dfd, "uevent", O_WRONLY);
@@ -132,7 +132,7 @@
 
         Uevent uevent;
         while (ReadUevent(&uevent)) {
-            if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
+            if (callback(uevent) == RegenerationAction::kStop) return RegenerationAction::kStop;
         }
     }
 
@@ -147,67 +147,49 @@
         if (d2 == 0) {
             close(fd);
         } else {
-            if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
-                return ListenerAction::kStop;
+            if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) {
+                return RegenerationAction::kStop;
             }
         }
     }
 
     // default is always to continue looking for uevents
-    return ListenerAction::kContinue;
+    return RegenerationAction::kContinue;
 }
 
-ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
-                                                        const ListenerCallback& callback) const {
+RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path,
+                                                            RegenerateCallback callback) const {
     std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
-    if (!d) return ListenerAction::kContinue;
+    if (!d) return RegenerationAction::kContinue;
 
     return RegenerateUeventsForDir(d.get(), callback);
 }
 
 static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
 
-void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
+void UeventListener::RegenerateUevents(RegenerateCallback callback) const {
     for (const auto path : kRegenerationPaths) {
-        if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
+        if (RegenerateUeventsForPath(path, callback) == RegenerationAction::kStop) return;
     }
 }
 
-void UeventListener::Poll(const ListenerCallback& callback,
-                          const std::optional<std::chrono::milliseconds> relative_timeout) const {
-    using namespace std::chrono;
-
+void UeventListener::DoPolling(PollCallback callback) const {
     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) {
-            PLOG(ERROR) << "poll() of uevent socket failed, continuing";
+        int nr = poll(&ufd, 1, -1);
+        if (nr <= 0) {
             continue;
         }
         if (ufd.revents & POLLIN) {
-            // We're non-blocking, so if we receive a poll event keep processing until
+            // We're non-blocking, so if we receive a poll event keep processing until there
             // we have exhausted all uevent messages.
             Uevent uevent;
             while (ReadUevent(&uevent)) {
-                if (callback(uevent) == ListenerAction::kStop) return;
+                callback(uevent);
             }
         }
     }
diff --git a/init/uevent_listener.h b/init/uevent_listener.h
index 0dae102..ba31aaa 100644
--- a/init/uevent_listener.h
+++ b/init/uevent_listener.h
@@ -19,9 +19,7 @@
 
 #include <dirent.h>
 
-#include <chrono>
 #include <functional>
-#include <optional>
 
 #include <android-base/unique_fd.h>
 
@@ -29,26 +27,26 @@
 
 #define UEVENT_MSG_LEN 2048
 
-enum class ListenerAction {
+enum class RegenerationAction {
     kStop = 0,  // Stop regenerating uevents as we've handled the one(s) we're interested in.
     kContinue,  // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
 };
 
-using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
+using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
+using PollCallback = std::function<void(const Uevent&)>;
 
 class UeventListener {
   public:
     UeventListener();
 
-    void RegenerateUevents(const ListenerCallback& callback) const;
-    ListenerAction RegenerateUeventsForPath(const std::string& path,
-                                            const ListenerCallback& callback) const;
-    void Poll(const ListenerCallback& callback,
-              const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;
+    void RegenerateUevents(RegenerateCallback callback) const;
+    RegenerationAction RegenerateUeventsForPath(const std::string& path,
+                                                RegenerateCallback callback) const;
+    void DoPolling(PollCallback callback) const;
 
   private:
     bool ReadUevent(Uevent* uevent) const;
-    ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;
+    RegenerationAction RegenerateUeventsForDir(DIR* d, RegenerateCallback callback) const;
 
     android::base::unique_fd device_fd_;
 };
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 4982b77..d121647 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -128,7 +128,15 @@
 void ColdBoot::UeventHandlerMain(unsigned int process_num, unsigned int total_processes) {
     for (unsigned int i = process_num; i < uevent_queue_.size(); i += total_processes) {
         auto& uevent = uevent_queue_[i];
-        device_handler_.HandleDeviceEvent(uevent);
+        if (uevent.action == "add" || uevent.action == "change" || uevent.action == "online") {
+            device_handler_.FixupSysPermissions(uevent.path, uevent.subsystem);
+        }
+
+        if (uevent.subsystem == "block") {
+            device_handler_.HandleBlockDeviceEvent(uevent);
+        } else {
+            device_handler_.HandleGenericDeviceEvent(uevent);
+        }
     }
     _exit(EXIT_SUCCESS);
 }
@@ -137,8 +145,16 @@
     uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
         HandleFirmwareEvent(uevent);
 
+        // This is the one mutable part of DeviceHandler, in which platform devices are
+        // added to a vector for later reference.  Since there is no communication after
+        // fork()'ing subprocess handlers, all platform devices must be in the vector before
+        // we fork, and therefore they must be handled in this loop.
+        if (uevent.subsystem == "platform") {
+            device_handler_.HandlePlatformDeviceEvent(uevent);
+        }
+
         uevent_queue_.emplace_back(std::move(uevent));
-        return ListenerAction::kContinue;
+        return RegenerationAction::kContinue;
     });
 }
 
@@ -266,10 +282,9 @@
         cold_boot.Run();
     }
 
-    uevent_listener.Poll([&device_handler](const Uevent& uevent) {
+    uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
         HandleFirmwareEvent(uevent);
         device_handler.HandleDeviceEvent(uevent);
-        return ListenerAction::kContinue;
     });
 
     return 0;
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index ada2ae4..fab38ed 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -37,7 +37,7 @@
 
   template <class F>
   void install(int signal, F&& f) {
-    MEM_LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+    if (signal != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
 
     handler_ = SignalFn(std::allocator_arg, allocator_,
                         [=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
diff --git a/libmemunreachable/log.h b/libmemunreachable/log.h
index 1725c53..10b83db 100644
--- a/libmemunreachable/log.h
+++ b/libmemunreachable/log.h
@@ -30,9 +30,6 @@
 
 #define MEM_LOG_ALWAYS_FATAL(...) async_safe_fatal(__VA_ARGS__)
 
-#define MEM_LOG_ALWAYS_FATAL_IF(cond, ...) \
-  ((__predict_false(cond)) ? async_safe_fatal(__VA_ARGS__) : (void)0)
-
 #else
 
 #include <log/log.h>
@@ -43,7 +40,6 @@
 #define MEM_ALOGI ALOGI
 
 #define MEM_LOG_ALWAYS_FATAL LOG_ALWAYS_FATAL
-#define MEM_LOG_ALWAYS_FATAL_IF LOG_ALWAYS_FATAL_IF
 
 #endif