fuchsia: Migrate off launchpad

Rather than using liblaunchpad.so to create processes, we now use
fdio_spawn.

Bug: crashpad:196
Change-Id: I28a7c12c823f0a0d120962edfce2e2197302b9cb
Reviewed-on: https://chromium-review.googlesource.com/1080234
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Adam Barth 2018-05-30 17:22:32 -07:00 committed by Commit Bot
parent dc22f05f61
commit 1299754179
7 changed files with 88 additions and 89 deletions

View File

@ -88,14 +88,10 @@ static_library("client") {
cflags = [ "/wd4201" ] # nonstandard extension used : nameless struct/union
}
if (crashpad_is_fuchsia) {
if (crashpad_is_in_fuchsia) {
deps += [
"//zircon/public/lib/launchpad",
]
} else {
libs = [ "launchpad" ]
}
if (crashpad_is_fuchsia && crashpad_is_in_fuchsia) {
deps += [
"//zircon/public/lib/fdio",
]
}
}

View File

@ -14,7 +14,7 @@
#include "client/crashpad_client.h"
#include <launchpad/launchpad.h>
#include <fdio/spawn.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
@ -69,20 +69,6 @@ bool CrashpadClient::StartHandler(
std::vector<const char*> argv;
ConvertArgvStrings(argv_strings, &argv);
// ConvertArgvStrings adds an unnecessary nullptr at the end of the argv list,
// which causes launchpad_set_args() to hang.
argv.pop_back();
launchpad_t* lp;
launchpad_create(zx_job_default(), argv[0], &lp);
launchpad_load_from_file(lp, argv[0]);
launchpad_set_args(lp, argv.size(), &argv[0]);
// TODO(scottmg): https://crashpad.chromium.org/bug/196, this is useful during
// bringup, but should probably be made minimal for real usage.
launchpad_clone(lp,
LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_STDIO |
LP_CLONE_ENVIRON | LP_CLONE_DEFAULT_JOB);
// Follow the same protocol as devmgr and crashlogger in Zircon (that is,
// process handle as handle 0, with type USER0, exception port handle as
@ -91,24 +77,39 @@ bool CrashpadClient::StartHandler(
// released here. Currently it is assumed that this process's default job
// handle is the exception port that should be monitored. In the future, it
// might be useful for this to be configurable by the client.
zx_handle_t handles[] = {ZX_HANDLE_INVALID, ZX_HANDLE_INVALID};
status =
zx_handle_duplicate(zx_job_default(), ZX_RIGHT_SAME_RIGHTS, &handles[0]);
constexpr size_t kActionCount = 2;
fdio_spawn_action_t actions[] = {
{.action = FDIO_SPAWN_ACTION_ADD_HANDLE,
.h = {.id = PA_HND(PA_USER0, 0), .handle = ZX_HANDLE_INVALID}},
{.action = FDIO_SPAWN_ACTION_ADD_HANDLE,
.h = {.id = PA_HND(PA_USER0, 1), .handle = ZX_HANDLE_INVALID}},
};
status = zx_handle_duplicate(
zx_job_default(), ZX_RIGHT_SAME_RIGHTS, &actions[0].h.handle);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "zx_handle_duplicate";
return false;
}
handles[1] = exception_port.release();
uint32_t handle_types[] = {PA_HND(PA_USER0, 0), PA_HND(PA_USER0, 1)};
actions[1].h.handle = exception_port.release();
launchpad_add_handles(lp, arraysize(handles), handles, handle_types);
const char* error_message;
char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
zx_handle_t child_raw;
status = launchpad_go(lp, &child_raw, &error_message);
// TODO(scottmg): https://crashpad.chromium.org/bug/196, FDIO_SPAWN_CLONE_ALL
// is useful during bringup, but should probably be made minimal for real
// usage.
status = fdio_spawn_etc(ZX_HANDLE_INVALID,
FDIO_SPAWN_CLONE_ALL,
argv[0],
argv.data(),
nullptr,
kActionCount,
actions,
&child_raw,
error_message);
base::ScopedZxHandle child(child_raw);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "launchpad_go: " << error_message;
ZX_LOG(ERROR, status) << "fdio_spawn_etc: " << error_message;
return false;
}

View File

@ -127,14 +127,10 @@ static_library("test") {
libs = [ "shell32.lib" ]
}
if (crashpad_is_fuchsia) {
if (crashpad_is_in_fuchsia) {
deps += [
"//zircon/public/lib/launchpad",
]
} else {
libs = [ "launchpad" ]
}
if (crashpad_is_fuchsia && crashpad_is_in_fuchsia) {
deps += [
"//zircon/public/lib/fdio",
]
}
}

View File

@ -14,8 +14,10 @@
#include "test/multiprocess_exec.h"
#include <launchpad/launchpad.h>
#include <fdio/io.h>
#include <fdio/spawn.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include "base/files/scoped_file.h"
@ -26,6 +28,21 @@
namespace crashpad {
namespace test {
namespace {
void AddPipe(fdio_spawn_action_t* action, int target_fd, int* fd_out) {
zx_handle_t handle;
uint32_t id;
zx_status_t status = fdio_pipe_half(&handle, &id);
ZX_CHECK(status < 0, status) << "Failed to create pipe.";
action->action = FDIO_SPAWN_ACTION_ADD_HANDLE;
action->h.id = PA_HND(PA_HND_TYPE(id), target_fd);
action->h.handle = handle;
*fd_out = status;
}
} // namespace
namespace internal {
struct MultiprocessInfo {
@ -38,10 +55,7 @@ struct MultiprocessInfo {
} // namespace internal
Multiprocess::Multiprocess()
: info_(nullptr),
code_(EXIT_SUCCESS),
reason_(kTerminationNormal) {
}
: info_(nullptr), code_(EXIT_SUCCESS), reason_(kTerminationNormal) {}
void Multiprocess::Run() {
// Set up and spawn the child process.
@ -122,8 +136,7 @@ void Multiprocess::RunChild() {
}
MultiprocessExec::MultiprocessExec()
: Multiprocess(), command_(), arguments_(), argv_() {
}
: Multiprocess(), command_(), arguments_(), argv_() {}
void MultiprocessExec::SetChildCommand(
const base::FilePath& command,
@ -147,37 +160,45 @@ void MultiprocessExec::PreFork() {
for (const std::string& argument : arguments_) {
argv_.push_back(argument.c_str());
}
argv_.push_back(nullptr);
ASSERT_EQ(info(), nullptr);
set_info(new internal::MultiprocessInfo());
}
void MultiprocessExec::MultiprocessChild() {
launchpad_t* lp;
launchpad_create(zx_job_default(), command_.value().c_str(), &lp);
launchpad_load_from_file(lp, command_.value().c_str());
launchpad_set_args(lp, argv_.size(), &argv_[0]);
constexpr size_t kActionCount = 3;
fdio_spawn_action_t actions[kActionCount];
int stdin_parent_side = -1;
AddPipe(&actions[0], STDIN_FILENO, &stdin_parent_side);
info()->stdin_write.reset(stdin_parent_side);
int stdout_parent_side = -1;
AddPipe(&actions[1], STDOUT_FILENO, &stdout_parent_side);
info()->stdout_read.reset(stdout_parent_side);
actions[2].action = FDIO_SPAWN_ACTION_CLONE_FD;
actions[2].fd.local_fd = STDERR_FILENO;
actions[2].fd.target_fd = STDERR_FILENO;
// Pass the filesystem namespace, parent environment, and default job to the
// child, but don't include any other file handles, preferring to set them
// up explicitly below.
launchpad_clone(
lp, LP_CLONE_FDIO_NAMESPACE | LP_CLONE_ENVIRON | LP_CLONE_DEFAULT_JOB);
uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO;
int stdin_parent_side;
launchpad_add_pipe(lp, &stdin_parent_side, STDIN_FILENO);
info()->stdin_write.reset(stdin_parent_side);
int stdout_parent_side;
launchpad_add_pipe(lp, &stdout_parent_side, STDOUT_FILENO);
info()->stdout_read.reset(stdout_parent_side);
launchpad_clone_fd(lp, STDERR_FILENO, STDERR_FILENO);
const char* error_message;
char error_message[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
zx_handle_t child;
zx_status_t status = launchpad_go(lp, &child, &error_message);
ZX_CHECK(status == ZX_OK, status) << "launchpad_go: " << error_message;
zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID,
flags,
command_.value().c_str(),
argv_.data(),
nullptr,
kActionCount,
actions,
&child,
error_message);
ZX_CHECK(status == ZX_OK, status) << "fdio_spawn_etc: " << error_message;
info()->child.reset(child);
}

View File

@ -49,7 +49,6 @@ if (crashpad_is_in_chromium) {
if (crashpad_is_fuchsia) {
libs = [
"launchpad",
"zircon",
]
}
@ -272,7 +271,6 @@ if (crashpad_is_in_chromium) {
if (crashpad_is_fuchsia) {
libs = [
"launchpad",
"zircon",
]
}

View File

@ -104,14 +104,6 @@ if (crashpad_is_mac || crashpad_is_fuchsia) {
"../third_party/mini_chromium:base",
"../util",
]
if (crashpad_is_fuchsia) {
if (crashpad_is_in_fuchsia) {
deps += [ "//zircon/public/lib/launchpad" ]
} else {
libs = [ "launchpad" ]
}
}
}
}

View File

@ -32,7 +32,7 @@
#include "util/string/split_string.h"
#if defined(OS_FUCHSIA)
#include <launchpad/launchpad.h>
#include <fdio/spawn.h>
#include <zircon/process.h>
#include <zircon/syscalls.h>
@ -48,7 +48,7 @@ void Usage(const std::string& me) {
"Start a Crashpad handler and have it handle crashes from COMMAND.\n"
"\n"
#if defined(OS_FUCHSIA)
"COMMAND is run via launchpad, so must be a qualified path to the subprocess to\n"
"COMMAND is run via fdio_spawn, so must be a qualified path to the subprocess to\n"
"be executed.\n"
#else
"COMMAND is run via execvp() so the PATH will be searched.\n"
@ -190,17 +190,12 @@ int RunWithCrashpadMain(int argc, char* argv[]) {
}
#if defined(OS_FUCHSIA)
// Fuchsia doesn't implement execvp(), launch with launchpad here.
launchpad_t* lp;
launchpad_create(zx_job_default(), argv[0], &lp);
launchpad_load_from_file(lp, argv[0]);
launchpad_set_args(lp, argc, argv);
launchpad_clone(lp, LP_CLONE_ALL);
const char* error_message;
zx_handle_t child;
zx_status_t status = launchpad_go(lp, &child, &error_message);
// Fuchsia doesn't implement execvp(), launch with fdio_spawn here.
zx_handle_t child = ZX_HANDLE_INVALID;
zx_status_t status = fdio_spawn(
ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, argv[0], argv, &child);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "launchpad_go: " << error_message;
ZX_LOG(ERROR, status) << "fdio_spawn failed";
return status == ZX_ERR_IO ? kExitExecENOENT : kExitExecFailure;
}