| // 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 |