summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Bao <tbao@google.com>2016-01-14 19:25:54 +0100
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-01-14 19:25:54 +0100
commit37e3c71da32f476e2658c57d0576e8f94e696ba1 (patch)
tree07e9ffbc0b8e27c64b84b08922d5407892fe7da6
parentMerge "uncrypt: avoid use-after-free" (diff)
parentrecovery: Fork a process for fuse when sideloading from SD card. (diff)
downloadandroid_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar.gz
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar.bz2
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar.lz
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar.xz
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.tar.zst
android_bootable_recovery-37e3c71da32f476e2658c57d0576e8f94e696ba1.zip
-rw-r--r--fuse_sdcard_provider.cpp74
-rw-r--r--fuse_sdcard_provider.h3
-rw-r--r--recovery.cpp61
3 files changed, 69 insertions, 69 deletions
diff --git a/fuse_sdcard_provider.cpp b/fuse_sdcard_provider.cpp
index eb6454f1d..df9631272 100644
--- a/fuse_sdcard_provider.cpp
+++ b/fuse_sdcard_provider.cpp
@@ -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;
}
diff --git a/fuse_sdcard_provider.h b/fuse_sdcard_provider.h
index dc2982ca0..bdc60f2ba 100644
--- a/fuse_sdcard_provider.h
+++ b/fuse_sdcard_provider.h
@@ -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
diff --git a/recovery.cpp b/recovery.cpp
index dace52f98..17e9eb66f 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -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