blob: eeb9574c8bcff308867f1a851a275d9d360421ba [file] [log] [blame]
// Copyright 2023 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 "unowned_component.h"
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/trace/event.h>
#include "component.h"
zx::result<std::unique_ptr<profiler::UnownedComponent>> profiler::UnownedComponent::Create(
const std::optional<std::string>& moniker, const std::optional<std::string>& url,
ComponentWatcher& component_watcher) {
std::optional<Moniker> parsed_moniker;
if (moniker.has_value()) {
zx::result parsed = profiler::Moniker::Parse(moniker.value_or(""));
if (parsed.is_error()) {
return parsed.take_error();
}
parsed_moniker = *parsed;
}
return zx::ok(std::make_unique<UnownedComponent>(url, parsed_moniker, component_watcher));
}
zx::result<> profiler::UnownedComponent::Attach(
const fidl::SyncClient<fuchsia_sys2::RealmQuery>& client, const Moniker& moniker) {
TRACE_DURATION("cpu_profiler", __PRETTY_FUNCTION__, "moniker", moniker.ToString());
fidl::Result<fuchsia_sys2::RealmQuery::GetInstance> result =
client->GetInstance(moniker.ToString());
if (result.is_error()) {
FX_LOGS(WARNING) << "Failed to find moniker: " << moniker.ToString() << ". "
<< result.error_value();
return result.error_value().is_domain_error()
? zx::error(ZX_ERR_BAD_PATH)
: zx::error(result.error_value().framework_error().status());
}
if (!result->instance().url()) {
return zx::error(ZX_ERR_BAD_PATH);
}
if (!result->instance().resolved_info() ||
!result->instance().resolved_info()->execution_info()) {
return component_watcher_.WatchForMoniker(
moniker.ToString(), [this](std::string moniker, std::string url) {
on_start_.value()(std::move(moniker), std::move(url));
});
}
on_start_.value()(moniker.ToString(), *result->instance().url());
return zx::ok();
}
zx::result<> profiler::UnownedComponent::Start(fxl::WeakPtr<Sampler> notify) {
TRACE_DURATION("cpu_profiler", __PRETTY_FUNCTION__);
on_start_ = profiler::MakeOnStartHandler(std::move(notify));
zx::result<fidl::ClientEnd<fuchsia_sys2::RealmQuery>> client_end =
component::Connect<fuchsia_sys2::RealmQuery>("/svc/fuchsia.sys2.RealmQuery.root");
if (client_end.is_error()) {
FX_LOGS(WARNING) << "Unable to connect to RealmQuery. Attaching to components isn't supported!";
return client_end.take_error();
}
fidl::SyncClient realm_query_client{std::move(*client_end)};
// If we don't have a moniker specified, that means we're waiting for a component with a matching
// url to show up.
if (!moniker_.has_value()) {
FX_DCHECK(url_.has_value()); // This should have been checked earlier in configuration
return component_watcher_.WatchForUrl(*url_, [this](std::string moniker, std::string url) {
on_start_.value()(std::move(moniker), std::move(url));
});
}
// If the component exists, we'll attach to it, if not, we'll need to wait for it to launch
fidl::Result<fuchsia_sys2::RealmQuery::GetInstance> result =
realm_query_client->GetInstance(moniker_->ToString());
if (result.is_error()) {
if (result.error_value().is_domain_error() &&
result.error_value().domain_error() == fuchsia_sys2::GetInstanceError::kInstanceNotFound) {
FX_LOGS(INFO) << "Watching for: " << moniker_->ToString();
return component_watcher_.WatchForMoniker(
moniker_->ToString(), [this, realm_query_client = std::move(realm_query_client)](
const std::string& moniker, const std::string& url) mutable {
auto res =
profiler::TraverseRealm(moniker_->ToString(),
[this, client = std::move(realm_query_client)](
const std::string& moniker_string) -> zx::result<> {
auto moniker = Moniker::Parse(moniker_string);
if (moniker.is_error()) {
return moniker.take_error();
}
return this->Attach(client, *moniker);
});
if (res.is_error()) {
FX_PLOGS(ERROR, res.status_value())
<< "Failed to recursively attach to moniker: " << moniker;
}
});
}
FX_LOGS(INFO) << "Invalid moniker: " << moniker_->ToString();
return zx::error(ZX_ERR_INVALID_ARGS);
}
return profiler::TraverseRealm(moniker_->ToString(),
[this, client = std::move(realm_query_client)](
const std::string& moniker_string) -> zx::result<> {
auto moniker = Moniker::Parse(moniker_string);
if (moniker.is_error()) {
return moniker.take_error();
}
return this->Attach(client, *moniker);
});
}
zx::result<> profiler::UnownedComponent::Stop() { return zx::ok(); }
zx::result<> profiler::UnownedComponent::Destroy() { return zx::ok(); }