blob: 4d10833786469b39088c630796a79cbcab934c12 [file] [log] [blame]
// Copyright 2022 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 "adb-shell.h"
#include <fidl/fuchsia.dash/cpp/wire.h>
#include <fidl/fuchsia.hardware.adb/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <fidl/fuchsia.sys2/cpp/wire.h>
#include <lib/async/cpp/task.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/syslog/cpp/macros.h>
#include <stdio.h>
#include <zircon/types.h>
#include "src/developer/adb/bin/adb-shell/adb_shell_config.h"
namespace adb_shell {
void AdbShell::ConnectToService(ConnectToServiceRequestView request,
ConnectToServiceCompleter::Sync& completer) {
auto status = AddShell({std::string(request->args.get())}, std::move(request->socket));
if (status != ZX_OK) {
completer.ReplyError(status);
return;
}
completer.ReplySuccess();
}
zx_status_t AdbShell::AddShell(std::optional<std::string> args, zx::socket server) {
auto impl = std::make_unique<AdbShellImpl>(svc_.borrow(), dispatcher_);
auto impl_ptr = impl.get();
{
fbl::AutoLock lock(&shell_lock_);
shells_.emplace_back(std::move(impl));
}
auto status = impl_ptr->Start(std::move(server), config_.dash_moniker(), args,
[this](AdbShellImpl* adb) { RemoveShell(adb); });
if (status != ZX_OK) {
FX_LOGS(ERROR) << "Failed to start adb shell instance - " << status;
return status;
}
return ZX_OK;
}
void AdbShell::RemoveShell(AdbShellImpl* impl) {
fbl::AutoLock lock(&shell_lock_);
auto itr = shells_.begin();
for (; itr != shells_.end(); itr++) {
if (itr->get() == impl) {
break;
}
}
if (itr != shells_.end()) {
shells_.erase(itr);
} else {
FX_LOGS(ERROR) << "Trying to erase a non existing shell instance " << impl;
}
}
zx_status_t AdbShellImpl::ResolveMoniker(std::string moniker) {
auto client_end = component::ConnectAt<fuchsia_sys2::LifecycleController>(
svc_, "fuchsia.sys2.LifecycleController.root");
if (client_end.is_error()) {
FX_LOGS(ERROR) << "Could not connect to dash launcher " << client_end.status_string();
return client_end.status_value();
}
fidl::WireSyncClient<fuchsia_sys2::LifecycleController> lifecycle_controller(
std::move(*client_end));
auto result = lifecycle_controller->ResolveInstance(fidl::StringView::FromExternal(moniker));
if (!result.ok()) {
FX_LOGS(ERROR) << "FIDL call to resolve moniker failed" << result.status();
return result.status();
}
if (result->is_error()) {
FX_LOGS(ERROR) << "Could not resolve moniker "
<< static_cast<uint32_t>(result.value().error_value());
return ZX_ERR_INTERNAL;
}
return ZX_OK;
}
zx_status_t AdbShellImpl::Start(zx::socket shell_server, std::string moniker,
std::optional<std::string> args,
fit::callback<void(AdbShellImpl*)> on_dead) {
auto resolve_result = ResolveMoniker(moniker);
if (resolve_result != ZX_OK) {
FX_LOGS(ERROR) << "Failed to resolve moniker " << moniker;
return resolve_result;
}
on_dead_ = std::move(on_dead);
auto client_end = component::ConnectAt<fuchsia_dash::Launcher>(svc_);
if (client_end.is_error()) {
FX_LOGS(ERROR) << "Could not connect to dash launcher " << client_end.status_string();
return client_end.status_value();
}
dash_client_.Bind(std::move(*client_end), dispatcher_, this);
fidl::StringView cmd = {};
if (args.has_value() && !args.value().empty()) {
cmd = fidl::StringView::FromExternal(args.value());
}
FX_LOGS(DEBUG) << "Calling Launch Socket with moniker " << moniker;
auto result = dash_client_.sync()->ExploreComponentOverSocket(
fidl::StringView::FromExternal(moniker), std::move(shell_server), {}, cmd,
fuchsia_dash::DashNamespaceLayout::kInstanceNamespaceIsRoot);
if (!result.ok()) {
FX_LOGS(ERROR) << "FIDL call to ExploreComponentOverSocket failed" << result.status();
return result.status();
}
if (result->is_error()) {
FX_LOGS(ERROR) << "ExploreComponentOverSocket failed "
<< static_cast<uint32_t>(result.value().error_value());
return static_cast<zx_status_t>(result->error_value());
}
return ZX_OK;
}
void AdbShellImpl::OnTerminated(fidl::WireEvent<fuchsia_dash::Launcher::OnTerminated>* event) {
FX_LOGS(DEBUG) << "Got OnTerminate Event.";
if (on_dead_) {
async::PostTask(dispatcher_,
[on_dead = std::move(on_dead_), impl = this]() mutable { on_dead(impl); });
}
}
} // namespace adb_shell