Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20e93123 authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge "init: poll in first stage mount if required devices are not found"

parents 137ee511 ccf0d393
Loading
Loading
Loading
Loading
+73 −47
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <stdlib.h>
#include <unistd.h>
#include <unistd.h>


#include <chrono>
#include <memory>
#include <memory>
#include <set>
#include <set>
#include <string>
#include <string>
@@ -35,6 +36,8 @@
#include "uevent_listener.h"
#include "uevent_listener.h"
#include "util.h"
#include "util.h"


using namespace std::chrono_literals;

// Class Declarations
// Class Declarations
// ------------------
// ------------------
class FirstStageMount {
class FirstStageMount {
@@ -49,11 +52,11 @@ class FirstStageMount {
    bool InitDevices();
    bool InitDevices();


  protected:
  protected:
    void InitRequiredDevices();
    bool InitRequiredDevices();
    void InitVerityDevice(const std::string& verity_device);
    bool InitVerityDevice(const std::string& verity_device);
    bool MountPartitions();
    bool MountPartitions();


    virtual RegenerationAction UeventCallback(const Uevent& uevent);
    virtual ListenerAction UeventCallback(const Uevent& uevent);


    // Pure virtual functions.
    // Pure virtual functions.
    virtual bool GetRequiredDevices() = 0;
    virtual bool GetRequiredDevices() = 0;
@@ -86,7 +89,7 @@ class FirstStageMountVBootV2 : public FirstStageMount {
    ~FirstStageMountVBootV2() override = default;
    ~FirstStageMountVBootV2() override = default;


  protected:
  protected:
    RegenerationAction UeventCallback(const Uevent& uevent) override;
    ListenerAction UeventCallback(const Uevent& uevent) override;
    bool GetRequiredDevices() override;
    bool GetRequiredDevices() override;
    bool SetUpDmVerity(fstab_rec* fstab_rec) override;
    bool SetUpDmVerity(fstab_rec* fstab_rec) override;
    bool InitAvbHandle();
    bool InitAvbHandle();
@@ -141,49 +144,60 @@ bool FirstStageMount::DoFirstStageMount() {
}
}


bool FirstStageMount::InitDevices() {
bool FirstStageMount::InitDevices() {
    if (!GetRequiredDevices()) return false;
    return GetRequiredDevices() && InitRequiredDevices();

    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
// Creates devices with uevent->partition_name matching one in the member variable
// required_devices_partition_names_. Found partitions will then be removed from it
// required_devices_partition_names_. Found partitions will then be removed from it
// for the subsequent member function to check which devices are NOT created.
// for the subsequent member function to check which devices are NOT created.
void FirstStageMount::InitRequiredDevices() {
bool FirstStageMount::InitRequiredDevices() {
    if (required_devices_partition_names_.empty()) {
    if (required_devices_partition_names_.empty()) {
        return;
        return true;
    }
    }


    if (need_dm_verity_) {
    if (need_dm_verity_) {
        const std::string dm_path = "/devices/virtual/misc/device-mapper";
        const std::string dm_path = "/devices/virtual/misc/device-mapper";
        uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path,
        bool found = false;
                                                  [this, &dm_path](const Uevent& uevent) {
        auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
            if (uevent.path == dm_path) {
            if (uevent.path == dm_path) {
                device_handler_.HandleDeviceEvent(uevent);
                device_handler_.HandleDeviceEvent(uevent);
                                                          return RegenerationAction::kStop;
                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;
        }
        }
                                                      return RegenerationAction::kContinue;
                                                  });
    }
    }


    uevent_listener_.RegenerateUevents(
    auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
        [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;
}
}


RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
    // Ignores everything that is not a block device.
    // Ignores everything that is not a block device.
    if (uevent.subsystem != "block") {
    if (uevent.subsystem != "block") {
        return RegenerationAction::kContinue;
        return ListenerAction::kContinue;
    }
    }


    if (!uevent.partition_name.empty()) {
    if (!uevent.partition_name.empty()) {
@@ -192,34 +206,46 @@ RegenerationAction FirstStageMount::UeventCallback(const Uevent& uevent) {
        // suffix when A/B is used.
        // suffix when A/B is used.
        auto iter = required_devices_partition_names_.find(uevent.partition_name);
        auto iter = required_devices_partition_names_.find(uevent.partition_name);
        if (iter != required_devices_partition_names_.end()) {
        if (iter != required_devices_partition_names_.end()) {
            LOG(VERBOSE) << __FUNCTION__ << "(): found partition: " << *iter;
            LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
            required_devices_partition_names_.erase(iter);
            required_devices_partition_names_.erase(iter);
            device_handler_.HandleDeviceEvent(uevent);
            device_handler_.HandleDeviceEvent(uevent);
            if (required_devices_partition_names_.empty()) {
            if (required_devices_partition_names_.empty()) {
                return RegenerationAction::kStop;
                return ListenerAction::kStop;
            } else {
            } else {
                return RegenerationAction::kContinue;
                return ListenerAction::kContinue;
            }
            }
        }
        }
    }
    }
    // Not found a partition or find an unneeded partition, continue to find others.
    // Not found a partition or find an unneeded partition, continue to find others.
    return RegenerationAction::kContinue;
    return ListenerAction::kContinue;
}
}


// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
// Creates "/dev/block/dm-XX" for dm-verity by running coldboot on /sys/block/dm-XX.
void FirstStageMount::InitVerityDevice(const std::string& verity_device) {
bool FirstStageMount::InitVerityDevice(const std::string& verity_device) {
    const std::string device_name(basename(verity_device.c_str()));
    const std::string device_name(basename(verity_device.c_str()));
    const std::string syspath = "/sys/block/" + device_name;
    const std::string syspath = "/sys/block/" + device_name;
    bool found = false;


    uevent_listener_.RegenerateUeventsForPath(
    auto verity_callback = [&device_name, &verity_device, this, &found](const Uevent& uevent) {
        syspath, [&device_name, &verity_device, this](const Uevent& uevent) {
        if (uevent.device_name == device_name) {
        if (uevent.device_name == device_name) {
            LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
            LOG(VERBOSE) << "Creating dm-verity device : " << verity_device;
            device_handler_.HandleDeviceEvent(uevent);
            device_handler_.HandleDeviceEvent(uevent);
                return RegenerationAction::kStop;
            found = true;
            return ListenerAction::kStop;
        }
        }
            return RegenerationAction::kContinue;
        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;
}
}


bool FirstStageMount::MountPartitions() {
bool FirstStageMount::MountPartitions() {
@@ -285,7 +311,7 @@ bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
        } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
        } else if (ret == FS_MGR_SETUP_VERITY_SUCCESS) {
            // The exact block device name (fstab_rec->blk_device) is changed to "/dev/block/dm-XX".
            // 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.
            // Needs to create it because ueventd isn't started in init first stage.
            InitVerityDevice(fstab_rec->blk_device);
            return InitVerityDevice(fstab_rec->blk_device);
        } else {
        } else {
            return false;
            return false;
        }
        }
@@ -345,7 +371,7 @@ bool FirstStageMountVBootV2::GetRequiredDevices() {
    return true;
    return true;
}
}


RegenerationAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
ListenerAction FirstStageMountVBootV2::UeventCallback(const Uevent& uevent) {
    // Check if this uevent corresponds to one of the required partitions and store its symlinks if
    // Check if this uevent corresponds to one of the required partitions and store its symlinks if
    // so, in order to create FsManagerAvbHandle later.
    // so, in order to create FsManagerAvbHandle later.
    // Note that the parent callback removes partitions from the list of required partitions
    // Note that the parent callback removes partitions from the list of required partitions
+34 −16
Original line number Original line Diff line number Diff line
@@ -121,8 +121,8 @@ bool UeventListener::ReadUevent(Uevent* uevent) const {
// make sure we don't overrun the socket's buffer.
// make sure we don't overrun the socket's buffer.
//
//


RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d,
                                                           RegenerateCallback callback) const {
                                                       const ListenerCallback& callback) const {
    int dfd = dirfd(d);
    int dfd = dirfd(d);


    int fd = openat(dfd, "uevent", O_WRONLY);
    int fd = openat(dfd, "uevent", O_WRONLY);
@@ -132,7 +132,7 @@ RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,


        Uevent uevent;
        Uevent uevent;
        while (ReadUevent(&uevent)) {
        while (ReadUevent(&uevent)) {
            if (callback(uevent) == RegenerationAction::kStop) return RegenerationAction::kStop;
            if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop;
        }
        }
    }
    }


@@ -147,49 +147,67 @@ RegenerationAction UeventListener::RegenerateUeventsForDir(DIR* d,
        if (d2 == 0) {
        if (d2 == 0) {
            close(fd);
            close(fd);
        } else {
        } else {
            if (RegenerateUeventsForDir(d2.get(), callback) == RegenerationAction::kStop) {
            if (RegenerateUeventsForDir(d2.get(), callback) == ListenerAction::kStop) {
                return RegenerationAction::kStop;
                return ListenerAction::kStop;
            }
            }
        }
        }
    }
    }


    // default is always to continue looking for uevents
    // default is always to continue looking for uevents
    return RegenerationAction::kContinue;
    return ListenerAction::kContinue;
}
}


RegenerationAction UeventListener::RegenerateUeventsForPath(const std::string& path,
ListenerAction UeventListener::RegenerateUeventsForPath(const std::string& path,
                                                            RegenerateCallback callback) const {
                                                        const ListenerCallback& callback) const {
    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
    std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path.c_str()), closedir);
    if (!d) return RegenerationAction::kContinue;
    if (!d) return ListenerAction::kContinue;


    return RegenerateUeventsForDir(d.get(), callback);
    return RegenerateUeventsForDir(d.get(), callback);
}
}


static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};


void UeventListener::RegenerateUevents(RegenerateCallback callback) const {
void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
    for (const auto path : kRegenerationPaths) {
    for (const auto path : kRegenerationPaths) {
        if (RegenerateUeventsForPath(path, callback) == RegenerationAction::kStop) return;
        if (RegenerateUeventsForPath(path, callback) == ListenerAction::kStop) return;
    }
    }
}
}


void UeventListener::DoPolling(PollCallback callback) const {
void UeventListener::Poll(const ListenerCallback& callback,
                          const std::optional<std::chrono::milliseconds> relative_timeout) const {
    using namespace std::chrono;

    pollfd ufd;
    pollfd ufd;
    ufd.events = POLLIN;
    ufd.events = POLLIN;
    ufd.fd = device_fd_;
    ufd.fd = device_fd_;


    auto start_time = steady_clock::now();

    while (true) {
    while (true) {
        ufd.revents = 0;
        ufd.revents = 0;
        int nr = poll(&ufd, 1, -1);

        if (nr <= 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";
            continue;
            continue;
        }
        }
        if (ufd.revents & POLLIN) {
        if (ufd.revents & POLLIN) {
            // We're non-blocking, so if we receive a poll event keep processing until there
            // We're non-blocking, so if we receive a poll event keep processing until
            // we have exhausted all uevent messages.
            // we have exhausted all uevent messages.
            Uevent uevent;
            Uevent uevent;
            while (ReadUevent(&uevent)) {
            while (ReadUevent(&uevent)) {
                callback(uevent);
                if (callback(uevent) == ListenerAction::kStop) return;
            }
            }
        }
        }
    }
    }
+10 −8
Original line number Original line Diff line number Diff line
@@ -19,7 +19,9 @@


#include <dirent.h>
#include <dirent.h>


#include <chrono>
#include <functional>
#include <functional>
#include <optional>


#include <android-base/unique_fd.h>
#include <android-base/unique_fd.h>


@@ -27,26 +29,26 @@


#define UEVENT_MSG_LEN 2048
#define UEVENT_MSG_LEN 2048


enum class RegenerationAction {
enum class ListenerAction {
    kStop = 0,  // Stop regenerating uevents as we've handled the one(s) we're interested in.
    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.
    kContinue,  // Continue regenerating uevents as we haven't seen the one(s) we're interested in.
};
};


using RegenerateCallback = std::function<RegenerationAction(const Uevent&)>;
using ListenerCallback = std::function<ListenerAction(const Uevent&)>;
using PollCallback = std::function<void(const Uevent&)>;


class UeventListener {
class UeventListener {
  public:
  public:
    UeventListener();
    UeventListener();


    void RegenerateUevents(RegenerateCallback callback) const;
    void RegenerateUevents(const ListenerCallback& callback) const;
    RegenerationAction RegenerateUeventsForPath(const std::string& path,
    ListenerAction RegenerateUeventsForPath(const std::string& path,
                                                RegenerateCallback callback) const;
                                            const ListenerCallback& callback) const;
    void DoPolling(PollCallback callback) const;
    void Poll(const ListenerCallback& callback,
              const std::optional<std::chrono::milliseconds> relative_timeout = {}) const;


  private:
  private:
    bool ReadUevent(Uevent* uevent) const;
    bool ReadUevent(Uevent* uevent) const;
    RegenerationAction RegenerateUeventsForDir(DIR* d, RegenerateCallback callback) const;
    ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const;


    android::base::unique_fd device_fd_;
    android::base::unique_fd device_fd_;
};
};
+3 −2
Original line number Original line Diff line number Diff line
@@ -138,7 +138,7 @@ void ColdBoot::RegenerateUevents() {
        HandleFirmwareEvent(uevent);
        HandleFirmwareEvent(uevent);


        uevent_queue_.emplace_back(std::move(uevent));
        uevent_queue_.emplace_back(std::move(uevent));
        return RegenerationAction::kContinue;
        return ListenerAction::kContinue;
    });
    });
}
}


@@ -266,9 +266,10 @@ int ueventd_main(int argc, char** argv) {
        cold_boot.Run();
        cold_boot.Run();
    }
    }


    uevent_listener.DoPolling([&device_handler](const Uevent& uevent) {
    uevent_listener.Poll([&device_handler](const Uevent& uevent) {
        HandleFirmwareEvent(uevent);
        HandleFirmwareEvent(uevent);
        device_handler.HandleDeviceEvent(uevent);
        device_handler.HandleDeviceEvent(uevent);
        return ListenerAction::kContinue;
    });
    });


    return 0;
    return 0;