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

Commit 632e99a0 authored by Elliott Hughes's avatar Elliott Hughes
Browse files

Switch ueventd to sendfile(2).

Bug: http://b/32826495
Test: booted and checked dmesg
Change-Id: Idfd813dfe6f512fdbc05b1411c7960e950e2f59b
parent 8cbc8952
Loading
Loading
Loading
Loading
+58 −110
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/sendfile.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
@@ -784,139 +785,87 @@ static void handle_device_event(struct uevent *uevent)
    }
}

static int load_firmware(int fw_fd, int loading_fd, int data_fd)
{
    struct stat st;
    long len_to_copy;
    int ret = 0;

    if(fstat(fw_fd, &st) < 0)
        return -1;
    len_to_copy = st.st_size;

    write(loading_fd, "1", 1);  /* start transfer */

    while (len_to_copy > 0) {
        char buf[PAGE_SIZE];
        ssize_t nr;
static void load_firmware(uevent* uevent, const std::string& root,
                          int fw_fd, size_t fw_size,
                          int loading_fd, int data_fd) {
    // Start transfer.
    android::base::WriteFully(loading_fd, "1", 1);

        nr = read(fw_fd, buf, sizeof(buf));
        if(!nr)
            break;
        if(nr < 0) {
            ret = -1;
            break;
        }
        if (!android::base::WriteFully(data_fd, buf, nr)) {
            ret = -1;
            break;
        }
        len_to_copy -= nr;
    // Copy the firmware.
    int rc = sendfile(data_fd, fw_fd, nullptr, fw_size);
    if (rc == -1) {
        PLOG(ERROR) << "firmware: sendfile failed { '" << root << "', '" << uevent->firmware << "' }";
    }

    if(!ret)
        write(loading_fd, "0", 1);  /* successful end of transfer */
    else
        write(loading_fd, "-1", 2); /* abort transfer */

    return ret;
    // Tell the firmware whether to abort or commit.
    const char* response = (rc != -1) ? "0" : "-1";
    android::base::WriteFully(loading_fd, response, strlen(response));
}

static int is_booting(void)
{
static int is_booting() {
    return access("/dev/.booting", F_OK) == 0;
}

static void process_firmware_event(struct uevent *uevent)
{
    char *root, *loading, *data;
    int l, loading_fd, data_fd, fw_fd;
    size_t i;
static void process_firmware_event(uevent* uevent) {
    int booting = is_booting();

    LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";

    l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
    if (l == -1)
        return;
    std::string root = android::base::StringPrintf("/sys%s", uevent->path);
    std::string loading = root + "/loading";
    std::string data = root + "/data";

    l = asprintf(&loading, "%sloading", root);
    if (l == -1)
        goto root_free_out;

    l = asprintf(&data, "%sdata", root);
    if (l == -1)
        goto loading_free_out;

    loading_fd = open(loading, O_WRONLY|O_CLOEXEC);
    if(loading_fd < 0)
        goto data_free_out;
    android::base::unique_fd loading_fd(open(loading.c_str(), O_WRONLY|O_CLOEXEC));
    if (loading_fd == -1) {
        PLOG(ERROR) << "couldn't open firmware loading fd for " << uevent->firmware;
        return;
    }

    data_fd = open(data, O_WRONLY|O_CLOEXEC);
    if(data_fd < 0)
        goto loading_close_out;
    android::base::unique_fd data_fd(open(data.c_str(), O_WRONLY|O_CLOEXEC));
    if (data_fd == -1) {
        PLOG(ERROR) << "couldn't open firmware data fd for " << uevent->firmware;
        return;
    }

try_loading_again:
    for (i = 0; i < arraysize(firmware_dirs); i++) {
        char *file = NULL;
        l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
        if (l == -1)
            goto data_free_out;
        fw_fd = open(file, O_RDONLY|O_CLOEXEC);
        free(file);
        if (fw_fd >= 0) {
            if (!load_firmware(fw_fd, loading_fd, data_fd)) {
                LOG(INFO) << "firmware: copy success { '" << root << "', '" << uevent->firmware << "' }";
            } else {
                LOG(ERROR) << "firmware: copy failure { '" << root << "', '" << uevent->firmware << "' }";
            }
            break;
    for (size_t i = 0; i < arraysize(firmware_dirs); i++) {
        std::string file = android::base::StringPrintf("%s/%s", firmware_dirs[i], uevent->firmware);
        android::base::unique_fd fw_fd(open(file.c_str(), O_RDONLY|O_CLOEXEC));
        struct stat sb;
        if (fw_fd != -1 && fstat(fw_fd, &sb) != -1) {
            load_firmware(uevent, root, fw_fd, sb.st_size, loading_fd, data_fd);
            return;
        }
    }
    if (fw_fd < 0) {

    if (booting) {
            /* If we're not fully booted, we may be missing
             * filesystems needed for firmware, wait and retry.
             */
        // If we're not fully booted, we may be missing
        // filesystems needed for firmware, wait and retry.
        usleep(100000);
        booting = is_booting();
        goto try_loading_again;
    }
        PLOG(ERROR) << "firmware: could not open '" << uevent->firmware << "'";
        write(loading_fd, "-1", 2);
        goto data_close_out;
    }

    close(fw_fd);
data_close_out:
    close(data_fd);
loading_close_out:
    close(loading_fd);
data_free_out:
    free(data);
loading_free_out:
    free(loading);
root_free_out:
    free(root);
}

static void handle_firmware_event(struct uevent *uevent)
{
    pid_t pid;
    LOG(ERROR) << "firmware: could not find firmware for " << uevent->firmware;

    if(strcmp(uevent->subsystem, "firmware"))
        return;
    // Write "-1" as our response to the kernel's firmware request, since we have nothing for it.
    write(loading_fd, "-1", 2);
}

    if(strcmp(uevent->action, "add"))
        return;
static void handle_firmware_event(uevent* uevent) {
    if (strcmp(uevent->subsystem, "firmware")) return;
    if (strcmp(uevent->action, "add")) return;

    /* we fork, to avoid making large memory allocations in init proper */
    pid = fork();
    if (!pid) {
    // Loading the firmware in a child means we can do that in parallel...
    // (We ignore SIGCHLD rather than wait for our children.)
    pid_t pid = fork();
    if (pid == 0) {
        Timer t;
        process_firmware_event(uevent);
        LOG(INFO) << "loading " << uevent->path << " took " << t.duration() << "s";
        _exit(EXIT_SUCCESS);
    } else if (pid < 0) {
        PLOG(ERROR) << "could not fork to process firmware event";
    } else if (pid == -1) {
        PLOG(ERROR) << "could not fork to process firmware event for " << uevent->firmware;
    }
}

@@ -1091,7 +1040,6 @@ void device_init() {
    LOG(INFO) << "Coldboot took " << t.duration() << "s.";
}

int get_device_fd()
{
int get_device_fd() {
    return device_fd;
}