blob: 3acd03079bbb77c2d9370e89a57ecf1c9730a0b1 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/developer/debug/debug_agent/component_launcher.h"
#include <fuchsia/sys/cpp/fidl.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/io.h>
#include <lib/syslog/cpp/macros.h>
#include <zircon/processargs.h>
#include "lib/sys/cpp/service_directory.h"
#include "src/developer/debug/shared/component_utils.h"
#include "src/developer/debug/shared/logging/logging.h"
namespace debug_agent {
namespace {
uint64_t kNextComponentId = 1;
// Attempts to link a zircon socket into the new component's file descriptor
// number represented by |fd|. If successful, the socket will be connected and
// a (one way) communication channel with that file descriptor will be made.
zx::socket AddStdio(int fd, fuchsia::sys::LaunchInfo* launch_info) {
zx::socket local;
zx::socket target;
zx_status_t status = zx::socket::create(0, &local, &target);
if (status != ZX_OK)
return zx::socket();
auto io = fuchsia::sys::FileDescriptor::New();
io->type0 = PA_HND(PA_FD, fd);
io->handle0 = std::move(target);
if (fd == STDOUT_FILENO) {
launch_info->out = std::move(io);
} else if (fd == STDERR_FILENO) {
launch_info->err = std::move(io);
} else {
FX_NOTREACHED() << "Invalid file descriptor: " << fd;
return zx::socket();
}
return local;
}
} // namespace
ComponentLauncher::ComponentLauncher(std::shared_ptr<sys::ServiceDirectory> services)
: services_(std::move(services)) {}
zx_status_t ComponentLauncher::Prepare(std::vector<std::string> argv,
ComponentDescription* description,
ComponentHandles* handles) {
FX_DCHECK(services_);
FX_DCHECK(!argv.empty());
auto pkg_url = argv.front();
debug_ipc::ComponentDescription url_desc;
if (!debug_ipc::ExtractComponentFromPackageUrl(pkg_url, &url_desc)) {
FX_LOGS(WARNING) << "Invalid package url: " << pkg_url;
return ZX_ERR_INVALID_ARGS;
}
// Prepare the launch info. The parameters to the component do not include
// the component URL.
launch_info_.url = argv.front();
if (argv.size() > 1) {
launch_info_.arguments.emplace();
for (size_t i = 1; i < argv.size(); i++)
launch_info_.arguments->push_back(std::move(argv[i]));
}
*description = {};
description->component_id = kNextComponentId++;
description->url = pkg_url;
description->process_name = url_desc.component_name;
description->filter = url_desc.component_name;
*handles = {};
handles->out = AddStdio(STDOUT_FILENO, &launch_info_);
handles->err = AddStdio(STDERR_FILENO, &launch_info_);
return ZX_OK;
};
fuchsia::sys::ComponentControllerPtr ComponentLauncher::Launch() {
FX_DCHECK(services_);
fuchsia::sys::LauncherSyncPtr launcher;
services_->Connect(launcher.NewRequest());
// Controller is a way to manage the newly created component. We need it in
// order to receive the terminated events. Sadly, there is no component
// started event. This also makes us need an async::Loop so that the fidl
// plumbing can work.
fuchsia::sys::ComponentControllerPtr controller;
launcher->CreateComponent(std::move(launch_info_), controller.NewRequest());
return controller;
}
} // namespace debug_agent