blob: 39a852795072d0500222f34f8bbe4e846f5af7e3 [file] [log] [blame]
// Copyright 2020 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.
#ifndef SRC_DEVICES_BIN_DRIVER_MANAGER_DRIVER_RUNNER_H_
#define SRC_DEVICES_BIN_DRIVER_MANAGER_DRIVER_RUNNER_H_
#include <fidl/fuchsia.component/cpp/wire.h>
#include <fidl/fuchsia.driver.crash/cpp/wire.h>
#include <fidl/fuchsia.driver.development/cpp/wire.h>
#include <fidl/fuchsia.driver.host/cpp/wire.h>
#include <fidl/fuchsia.driver.index/cpp/wire.h>
#include <fidl/fuchsia.driver.token/cpp/fidl.h>
#include <fidl/fuchsia.ldsvc/cpp/wire.h>
#include <fidl/fuchsia.power.broker/cpp/fidl.h>
#include <fidl/fuchsia.power.system/cpp/fidl.h>
#include <lib/async/cpp/wait.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/fit/function.h>
#include <lib/fpromise/promise.h>
#include <lib/inspect/component/cpp/component.h>
#include <lib/inspect/cpp/inspect.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <memory>
#include <unordered_set>
#include <fbl/intrusive_double_list.h>
#include "fidl/fuchsia.power.broker/cpp/natural_types.h"
#include "src/devices/bin/driver_loader/loader.h"
#include "src/devices/bin/driver_manager/bind/bind_manager.h"
#include "src/devices/bin/driver_manager/bootup_tracker.h"
#include "src/devices/bin/driver_manager/composite/composite_manager_bridge.h"
#include "src/devices/bin/driver_manager/composite/composite_node_spec_manager.h"
#include "src/devices/bin/driver_manager/dictionary_util.h"
#include "src/devices/bin/driver_manager/driver_host.h"
#include "src/devices/bin/driver_manager/driver_host_runner.h"
#include "src/devices/bin/driver_manager/memory_attribution.h"
#include "src/devices/bin/driver_manager/node.h"
#include "src/devices/bin/driver_manager/offer_injection.h"
#include "src/devices/bin/driver_manager/runner.h"
#include "src/devices/bin/driver_manager/shutdown/node_removal_tracker.h"
#include "src/devices/bin/driver_manager/shutdown/node_remover.h"
#include "src/devices/lib/log/log.h"
// Note, all of the logic here assumes we are operating on a single-threaded
// dispatcher. It is not safe to use a multi-threaded dispatcher with this code.
// TODO(https://fxbug.dev/479569256) Refactor DriverRunner to separate out power-related code
// with the goal of making things more maintainable and readable.
namespace driver_manager {
class DriverRunner : public fidl::WireServer<fuchsia_driver_framework::CompositeNodeManager>,
public fidl::WireServer<fuchsia_driver_index::DriverNotifier>,
public fidl::WireServer<fuchsia_driver_crash::CrashIntrospect>,
public fidl::Server<fuchsia_driver_token::NodeBusTopology>,
public fidl::WireServer<fuchsia_power_broker::ElementRunner>,
public fidl::WireServer<fuchsia_power_system::CpuElementManager>,
public BindManagerBridge,
public CompositeManagerBridge,
public std::enable_shared_from_this<DriverRunner>,
public NodeManager,
public NodeRemover {
using LoaderServiceFactory = fit::function<zx::result<fidl::ClientEnd<fuchsia_ldsvc::Loader>>()>;
using DynamicLinkerServiceFactory =
fit::function<zx::result<fidl::ClientEnd<fuchsia_driver_loader::DriverHostLauncher>>()>;
using CallbackSet = std::vector<fit::callback<void()>>;
using PowerDependencyToken = fuchsia_power_broker::DependencyToken;
public:
// Args required to enable dynamic linking
struct DynamicLinkerArgs {
DynamicLinkerServiceFactory linker_service_factory;
std::unique_ptr<DriverHostRunner> driver_host_runner;
};
// |Dynamic_linker_args| should be set if dynamic linking is available.
DriverRunner(fidl::ClientEnd<fuchsia_component::Realm> realm,
fidl::ClientEnd<fuchsia_component::Introspector> introspector,
fidl::ClientEnd<fuchsia_component_sandbox::CapabilityStore> capability_store,
fidl::ClientEnd<fuchsia_driver_index::DriverIndex> driver_index,
inspect::ComponentInspector& inspect, LoaderServiceFactory loader_service_factory,
async_dispatcher_t* dispatcher, bool enable_test_shutdown_delays,
OfferInjector offer_injector,
fidl::ClientEnd<fuchsia_power_broker::Topology> topology_client,
std::optional<DynamicLinkerArgs> dynamic_linker_args = std::nullopt,
std::optional<fidl::ClientEnd<fuchsia_power_system::CpuElementManager>>
cpu_element_mgr = std::nullopt,
bool wait_for_storage_token = false);
// fidl::WireServer<fuchsia_driver_framework::CompositeNodeManager> interface
void AddSpec(AddSpecRequestView request, AddSpecCompleter::Sync& completer) override;
// fidl::WireServer<fuchsia_driver_index::DriverNotifier>
void NewDriverAvailable(NewDriverAvailableCompleter::Sync& completer) override;
// fidl::WireServer<fuchsia_driver_crash::CrashIntrospect>
void FindDriverCrash(FindDriverCrashRequestView request,
FindDriverCrashCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_driver_framework::CompositeNodeManager> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
// fidl::WireServer<fuchsia_driver_token::NodeBusTopology>
void Get(GetRequest& request, GetCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_driver_token::NodeBusTopology> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
void SetLevel(SetLevelRequestView request, SetLevelCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_power_broker::ElementRunner> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
void GetCpuDependencyToken(GetCpuDependencyTokenCompleter::Sync& completer) override;
void AddExecutionStateDependency(AddExecutionStateDependencyRequestView request,
AddExecutionStateDependencyCompleter::Sync& completer) override;
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_power_system::CpuElementManager> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override;
// CompositeManagerBridge interface
void BindNodesForCompositeNodeSpec() override;
void AddSpecToDriverIndex(fuchsia_driver_framework::wire::CompositeNodeSpec group,
AddToIndexCallback callback) override;
// NodeManager interface
// Create a driver component with `url` against a given `node`.
zx::result<> StartDriver(Node& node, std::string_view url,
fuchsia_driver_framework::DriverPackageType package_type) override;
// NodeManager interface
// Waits for boot to complete before invoking the callback.
void WaitForBootup(fit::callback<void()> callback) override;
// NodeManager interface
// Shutdown hooks called by the shutdown manager
void ShutdownAllDrivers(fit::callback<void()> callback) override {
fdf_log::info("Driver Runner invokes shutdown all drivers");
removal_tracker_.set_all_callback(std::move(callback));
root_node_->Remove(RemovalSet::kAll, &removal_tracker_);
removal_tracker_.FinishEnumeration();
}
void ShutdownPkgDrivers(fit::callback<void()> callback) override {
removal_tracker_.set_pkg_callback(std::move(callback));
root_node_->Remove(RemovalSet::kPackage, &removal_tracker_);
removal_tracker_.FinishEnumeration();
}
void SetOnRemovalTimeoutCallback(fit::callback<void()> callback) override {
removal_tracker_.SetOnRemovalTimeoutCallback(std::move(callback));
}
void RebindComposite(std::string spec, std::optional<std::string> driver_url,
fit::callback<void(zx::result<>)> callback) override;
void RebindCompositesWithDriver(const std::string& url,
fit::callback<void(size_t)> complete_callback);
bool IsTestShutdownDelayEnabled() const override { return enable_test_shutdown_delays_; }
std::weak_ptr<std::mt19937> GetShutdownTestRng() const override {
return shutdown_test_delay_rng_;
}
void PublishComponentRunner(component::OutgoingDirectory& outgoing);
zx::result<> StartRootDriver(std::string_view url);
// Register a proxy driver called 'Devfs-Driver' that will advertise services that correspond
// to the protocols offered by devfs class paths. This call will start the driver
// registration, but that registration will not be complete until the component framework
// calls the AddChild callback. That callback will then update |devfs| with an outgoing
// directory and a ComponentController. This function should only be called once when the
// driver manager is starting, and will no longer be needed when devfs migration is complete.
void StartDevfsDriver(std::shared_ptr<driver_manager::Devfs>& devfs);
// Goes through the orphan list and attempts the bind them again. Sends nodes that are still
// orphaned back to the orphan list. Tracks the result of the bindings and then when finished
// uses the result_callback to report the results.
void TryBindAllAvailable(
NodeBindingInfoResultCallback result_callback =
[](fidl::VectorView<fuchsia_driver_development::wire::NodeBindingInfo>) {});
// Restarts all the nodes that are colocated with a driver with the given |url|.
zx::result<uint32_t> RestartNodesColocatedWithDriverUrl(
std::string_view url, fuchsia_driver_development::RestartRematchFlags rematch_flags);
void RestartWithDictionary(fidl::StringView moniker,
fuchsia_component_sandbox::wire::DictionaryRef dictionary,
zx::eventpair reset_eventpair);
std::unordered_set<const DriverHost*> DriverHostsWithDriverUrl(std::string_view url);
fpromise::promise<inspect::Inspector> Inspect() const;
bool SuspendEnabled() override { return power_topology_.is_valid(); }
std::vector<fuchsia_driver_development::wire::CompositeNodeInfo> GetCompositeListInfo(
fidl::AnyArena& arena) const;
fidl::WireClient<fuchsia_driver_index::DriverIndex>& driver_index() { return driver_index_; }
std::shared_ptr<Node> root_node() const { return root_node_; }
// Only exposed for testing.
void BootupDoneForTesting() { bootup_tracker_->BootupDoneForTesting(); }
CompositeNodeSpecManager& composite_node_spec_manager() { return composite_node_spec_manager_; }
const BindManager& bind_manager() const { return bind_manager_; }
driver_manager::Runner& runner_for_tests() { return runner_; }
driver_manager::DriverHostRunner* driver_host_runner_for_tests() {
return dynamic_linker_args_.has_value() ? dynamic_linker_args_->driver_host_runner.get()
: nullptr;
}
const fbl::DoublyLinkedList<std::unique_ptr<DriverHostComponent>>& driver_hosts() const {
return driver_hosts_;
}
void AddLeaseControlChannel(fidl::ClientEnd<fuchsia_power_broker::LeaseControl> lease) override;
std::optional<fuchsia_power_broker::DependencyToken> StorageElementToken() override;
void CreateStoragePowerElement(fuchsia_power_broker::DependencyToken driver_token,
fuchsia_power_broker::PowerLevel power_level,
fit::callback<void()> post_creation);
void PublishCpuElementManager(component::OutgoingDirectory& outgoing);
private:
// NodeManager interface.
// Attempt to bind `node`. A nullptr for result_tracker is acceptable if the caller doesn't
// intend to track the results.
void Bind(Node& node, std::shared_ptr<BindResultTracker> result_tracker) override;
void BindToUrl(Node& node, std::string_view driver_url_suffix,
std::shared_ptr<BindResultTracker> result_tracker) override;
DriverHost* GetDriverHost(std::string_view driver_host_name_for_colocation) override;
zx::result<DriverHost*> CreateDriverHost(
bool use_next_vdso, std::string_view driver_host_name_for_colocation) override;
// Creates the driver host component, loads the driver host using dynamic linking,
// and calls |cb| on completion. |cb| will only be called if the return value is zx::ok.
void CreateDriverHostDynamicLinker(
std::string_view driver_host_name_for_colocation,
fit::callback<void(zx::result<DriverHost*>)> completion_cb) override;
bool IsDriverHostValid(DriverHost* driver_host) const override;
DictionaryUtil& dictionary_util() override { return dictionary_util_; }
MemoryAttributor& memory_attributor() override { return memory_attributor_; }
// BindManagerBridge interface.
zx::result<std::string> StartDriver(
Node& node, fuchsia_driver_framework::wire::DriverInfo driver_info) override;
zx::result<BindSpecResult> BindToParentSpec(fidl::AnyArena& arena,
CompositeParents composite_parents,
std::weak_ptr<Node> node,
bool enable_multibind) override;
void RequestMatchFromDriverIndex(
fuchsia_driver_index::wire::MatchDriverArgs args,
fit::callback<void(fidl::WireUnownedResult<fuchsia_driver_index::DriverIndex::MatchDriver>&)>
match_callback) override;
void RequestRebindFromDriverIndex(std::string spec, std::optional<std::string> driver_url_suffix,
fit::callback<void(zx::result<>)> callback) override;
void OnBindingStateChanged() override { bootup_tracker_->NotifyBindingChanged(); }
zx::result<> CreateDriverHostComponent(std::string moniker,
fidl::ServerEnd<fuchsia_io::Directory> exposed_dir,
std::shared_ptr<bool> exposed_dir_connected,
bool use_next_vdso);
void CreatePowerElement(std::string_view name,
fuchsia_power_broker::DependencyToken element_token,
std::vector<fuchsia_power_broker::DependencyToken> deps,
fidl::ServerEnd<fuchsia_power_broker::ElementControl> control,
fidl::ClientEnd<fuchsia_power_broker::ElementRunner> runner,
fidl::ServerEnd<fuchsia_power_broker::Lessor> lessor,
Collection for_collection,
fit::callback<void(zx::result<bool>)> cb) override;
void RegisterStorageWithSag();
void OnBootupComplete();
uint64_t next_driver_host_id_ = 0;
fidl::WireClient<fuchsia_driver_index::DriverIndex> driver_index_;
LoaderServiceFactory loader_service_factory_;
DictionaryUtil dictionary_util_;
fidl::ServerBindingGroup<fuchsia_driver_framework::CompositeNodeManager> manager_bindings_;
fidl::ServerBindingGroup<fuchsia_driver_crash::CrashIntrospect> crash_introspect_bindings_;
fidl::ServerBindingGroup<fuchsia_driver_token::NodeBusTopology> bus_topo_bindings_;
fidl::ServerBindingGroup<fuchsia_driver_index::DriverNotifier> driver_notifier_bindings_;
fidl::ServerBindingGroup<fuchsia_power_broker::ElementRunner> storage_element_runner_;
fidl::ServerBindingGroup<fuchsia_power_system::CpuElementManager> cpu_element_server_;
async_dispatcher_t* const dispatcher_;
std::shared_ptr<Node> root_node_;
// Manages composite node specs.
CompositeNodeSpecManager composite_node_spec_manager_;
// Manages driver binding.
BindManager bind_manager_;
driver_manager::Runner runner_;
NodeRemovalTracker removal_tracker_;
std::shared_ptr<BootupTracker> bootup_tracker_;
fbl::DoublyLinkedList<std::unique_ptr<DriverHostComponent>> driver_hosts_;
// True if the driver manager should inject test delays in the shutdown process. Set by the
// structured config.
bool enable_test_shutdown_delays_;
// RNG engine for the shutdown test delays. For reproducibility reasons, only one engine
// should be used.
std::shared_ptr<std::mt19937> shutdown_test_delay_rng_;
// Set if dynamic linking is available.
std::optional<DynamicLinkerArgs> dynamic_linker_args_;
// TODO(https://fxbug.dev/349831408): for now we use the same dynamic linker client
// channel for each driver host.
std::optional<fidl::WireSharedClient<fuchsia_driver_loader::DriverHostLauncher>>
driver_host_launcher_;
fidl::Client<fuchsia_power_broker::Topology> power_topology_;
fidl::ClientEnd<fuchsia_power_broker::Lessor> storage_lessor_;
std::vector<fidl::ClientEnd<fuchsia_power_broker::LeaseControl>> leases_;
MemoryAttributor memory_attributor_;
// Either a vector of callbacks to run when we get a storage token or the token once we
// receive it.
std::variant<CallbackSet, PowerDependencyToken> storage_callbacks_or_token_ =
std::vector<fit::callback<void()>>();
fidl::Client<fuchsia_power_broker::ElementControl> storage_control_;
std::optional<fidl::Client<fuchsia_power_system::CpuElementManager>> cpu_element_client_;
fuchsia_power_broker::DependencyToken cpu_token_;
bool wait_for_storage_token_from_driver_;
};
Collection ToCollection(const Node& node, fuchsia_driver_framework::DriverPackageType package_type);
} // namespace driver_manager
#endif // SRC_DEVICES_BIN_DRIVER_MANAGER_DRIVER_RUNNER_H_