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

Commit 37e3c71d authored by Tao Bao's avatar Tao Bao Committed by Gerrit Code Review
Browse files

Merge "recovery: Fork a process for fuse when sideloading from SD card."

parents 0305fcec cdcf28f5
Loading
Loading
Loading
Loading
+11 −63
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -60,81 +59,30 @@ static void close_file(void* cookie) {
    close(fd->fd);
}

struct token {
    pthread_t th;
    const char* path;
    int result;
};

static void* run_sdcard_fuse(void* cookie) {
    token* t = reinterpret_cast<token*>(cookie);

bool start_sdcard_fuse(const char* path) {
    struct stat sb;
    if (stat(t->path, &sb) < 0) {
        fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno));
        t->result = -1;
        return NULL;
    if (stat(path, &sb) == -1) {
        fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
        return false;
    }

    struct file_data fd;
    struct provider_vtab vtab;

    fd.fd = open(t->path, O_RDONLY);
    if (fd.fd < 0) {
        fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno));
        t->result = -1;
        return NULL;
    file_data fd;
    fd.fd = open(path, O_RDONLY);
    if (fd.fd == -1) {
        fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
        return false;
    }
    fd.file_size = sb.st_size;
    fd.block_size = 65536;

    provider_vtab vtab;
    vtab.read_block = read_block_file;
    vtab.close = close_file;

    t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size);
    return NULL;
}

// How long (in seconds) we wait for the fuse-provided package file to
// appear, before timing out.
#define SDCARD_INSTALL_TIMEOUT 10

void* start_sdcard_fuse(const char* path) {
    token* t = new token;

    t->path = path;
    pthread_create(&(t->th), NULL, run_sdcard_fuse, t);

    struct stat st;
    int i;
    for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
        if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
            if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
                sleep(1);
                continue;
            } else {
                return NULL;
            }
        }
    }

    // The installation process expects to find the sdcard unmounted.
    // Unmount it with MNT_DETACH so that our open file continues to
    // work but new references see it as unmounted.
    umount2("/sdcard", MNT_DETACH);

    return t;
}

void finish_sdcard_fuse(void* cookie) {
    if (cookie == NULL) return;
    token* t = reinterpret_cast<token*>(cookie);

    // Calling stat() on this magic filename signals the fuse
    // filesystem to shut down.
    struct stat st;
    stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);

    pthread_join(t->th, NULL);
    delete t;
    return run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size) == 0;
}
+1 −2
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
#ifndef __FUSE_SDCARD_PROVIDER_H
#define __FUSE_SDCARD_PROVIDER_H

void* start_sdcard_fuse(const char* path);
void finish_sdcard_fuse(void* token);
bool start_sdcard_fuse(const char* path);

#endif
+57 −4
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <sys/klog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

@@ -833,6 +834,10 @@ static void choose_recovery_file(Device* device) {
    }
}

// How long (in seconds) we wait for the fuse-provided package file to
// appear, before timing out.
#define SDCARD_INSTALL_TIMEOUT 10

static int apply_from_sdcard(Device* device, bool* wipe_cache) {
    modified_flash = true;

@@ -850,14 +855,62 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {

    ui->Print("\n-- Install %s ...\n", path);
    set_sdcard_update_bootloader_message();
    void* token = start_sdcard_fuse(path);

    int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
    // We used to use fuse in a thread as opposed to a process. Since accessing
    // through fuse involves going from kernel to userspace to kernel, it leads
    // to deadlock when a page fault occurs. (Bug: 26313124)
    pid_t child;
    if ((child = fork()) == 0) {
        bool status = start_sdcard_fuse(path);

        _exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
    }

    // FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child
    // process is ready.
    int result = INSTALL_ERROR;
    int status;
    bool waited = false;
    for (int i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
        if (waitpid(child, &status, WNOHANG) == -1) {
            result = INSTALL_ERROR;
            waited = true;
            break;
        }

        struct stat sb;
        if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &sb) == -1) {
            if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
                sleep(1);
                continue;
            } else {
                LOGE("Timed out waiting for the fuse-provided package.\n");
                result = INSTALL_ERROR;
                kill(child, SIGKILL);
                break;
            }
        }

        result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
                                 TEMPORARY_INSTALL_FILE, false);
        break;
    }

    if (!waited) {
        // Calling stat() on this magic filename signals the fuse
        // filesystem to shut down.
        struct stat sb;
        stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &sb);

        waitpid(child, &status, 0);
    }

    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
        LOGE("Error exit from the fuse process: %d\n", WEXITSTATUS(status));
    }

    finish_sdcard_fuse(token);
    ensure_path_unmounted(SDCARD_ROOT);
    return status;
    return result;
}

// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER.  Returning NO_ACTION