blob: cb6fc4bbaa21adb9932feb0d97edcde59f5a1d24 [file] [log] [blame]
// Copyright 2017 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_COORDINATOR_H_
#define SRC_DEVICES_BIN_DRIVER_MANAGER_COORDINATOR_H_
#include <fidl/fuchsia.boot/cpp/wire.h>
#include <fidl/fuchsia.device.manager/cpp/wire.h>
#include <fidl/fuchsia.driver.development/cpp/wire.h>
#include <fidl/fuchsia.driver.framework/cpp/wire.h>
#include <fidl/fuchsia.driver.index/cpp/wire.h>
#include <fidl/fuchsia.driver.registrar/cpp/wire.h>
#include <fidl/fuchsia.fshost/cpp/wire.h>
#include <fidl/fuchsia.hardware.power.statecontrol/cpp/wire.h>
#include <fidl/fuchsia.power.manager/cpp/wire.h>
#include <lib/async/cpp/wait.h>
#include <lib/ddk/binding.h>
#include <lib/ddk/device.h>
#include <lib/fidl/llcpp/server.h>
#include <lib/stdcompat/optional.h>
#include <lib/svc/outgoing.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/channel.h>
#include <lib/zx/event.h>
#include <lib/zx/job.h>
#include <lib/zx/process.h>
#include <lib/zx/status.h>
#include <lib/zx/vmo.h>
#include <zircon/types.h>
#include <memory>
#include <string_view>
#include <utility>
#include <fbl/auto_lock.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/string.h>
#include <fbl/vector.h>
#include "lib/async/dispatcher.h"
#include "src/devices/bin/driver_manager/bind_driver_manager.h"
#include "src/devices/bin/driver_manager/debug_dump.h"
#include "src/devices/bin/driver_manager/devfs.h"
#include "src/devices/bin/driver_manager/device.h"
#include "src/devices/bin/driver_manager/driver.h"
#include "src/devices/bin/driver_manager/driver_host.h"
#include "src/devices/bin/driver_manager/driver_loader.h"
#include "src/devices/bin/driver_manager/inspect.h"
#include "src/devices/bin/driver_manager/metadata.h"
#include "src/devices/bin/driver_manager/package_resolver.h"
#include "src/devices/bin/driver_manager/system_state_manager.h"
#include "src/devices/bin/driver_manager/v1/device_manager.h"
#include "src/devices/bin/driver_manager/v1/firmware_loader.h"
#include "src/devices/bin/driver_manager/v1/init_task.h"
#include "src/devices/bin/driver_manager/v1/resume_task.h"
#include "src/devices/bin/driver_manager/v1/suspend_resume_manager.h"
#include "src/devices/bin/driver_manager/v1/suspend_task.h"
#include "src/devices/bin/driver_manager/v1/unbind_task.h"
#include "src/lib/storage/vfs/cpp/pseudo_dir.h"
namespace statecontrol_fidl = fuchsia_hardware_power_statecontrol;
using statecontrol_fidl::wire::SystemPowerState;
namespace fdf = fuchsia_driver_framework;
namespace fdi = fuchsia_driver_index;
class BindDriverManager;
class DebugDump;
class DeviceManager;
class DriverHostLoaderService;
class FirmwareLoader;
class FsProvider;
class SuspendResumeManager;
class SystemStateManager;
constexpr zx::duration kDefaultResumeTimeout = zx::sec(30);
constexpr zx::duration kDefaultSuspendTimeout = zx::sec(30);
using ResumeCallback = std::function<void(zx_status_t)>;
// The action to take when we witness a driver host crash.
enum class DriverHostCrashPolicy {
// Restart the driver host, with exponential backoff, up to 3 times.
// This will only be triggered if the driver host which host's the driver which created the
// parent device being bound to doesn't also crash.
// TODO(fxbug.dev/66442): Handle composite devices better (they don't seem to restart with this
// policy set).
kRestartDriverHost,
// Reboot the system via the power manager.
kRebootSystem,
// Don't take any action, other than cleaning up some internal driver manager state.
kDoNothing,
};
struct CoordinatorConfig {
// Initial root resource from the kernel.
zx::resource root_resource;
// Job for all driver_hosts.
zx::job driver_host_job;
// Event that is signaled by the kernel in OOM situation.
zx::event oom_event;
// Client for the Arguments service.
fidl::WireSyncClient<fuchsia_boot::Arguments>* boot_args;
// Client for the DriverIndex.
fidl::WireSharedClient<fdi::DriverIndex> driver_index;
// Whether we require /system.
bool require_system = false;
// Whether to output logs to debuglog.
bool log_to_debuglog = false;
// Whether to enable verbose logging.
bool verbose = false;
// Whether to allow loading drivers ephemerally. This should only be enabled on eng builds.
bool enable_ephemeral = false;
// Timeout for system wide suspend
zx::duration suspend_timeout = kDefaultSuspendTimeout;
// Timeout for system wide resume
zx::duration resume_timeout = kDefaultResumeTimeout;
// System will be transitioned to this system power state during
// component shutdown.
SystemPowerState default_shutdown_system_state = SystemPowerState::kReboot;
// Something to clone a handle from the environment to pass to a Devhost.
FsProvider* fs_provider = nullptr;
// The path prefix to find binaries, drivers, etc. Typically this is "/boot/", but in test
// environments this might be different.
std::string path_prefix = "/boot/";
// The decision to make when we encounter a driver host crash.
DriverHostCrashPolicy crash_policy = DriverHostCrashPolicy::kRestartDriverHost;
};
class Coordinator : public fidl::WireServer<fuchsia_driver_development::DriverDevelopment>,
public fidl::WireServer<fuchsia_device_manager::Administrator>,
public fidl::WireServer<fuchsia_driver_registrar::DriverRegistrar> {
public:
Coordinator(const Coordinator&) = delete;
Coordinator& operator=(const Coordinator&) = delete;
Coordinator(Coordinator&&) = delete;
Coordinator& operator=(Coordinator&&) = delete;
Coordinator(CoordinatorConfig config, InspectManager* inspect_manager,
async_dispatcher_t* dispatcher, async_dispatcher_t* firmware_dispatcher);
~Coordinator();
zx_status_t InitOutgoingServices(const fbl::RefPtr<fs::PseudoDir>& svc_dir);
zx::status<> PublishDriverDevelopmentService(const fbl::RefPtr<fs::PseudoDir>& svc_dir);
zx::status<> PublishDriverRegistrarService(const fbl::RefPtr<fs::PseudoDir>& svc_dir);
// Initialization functions for DFv1. InitCoreDevices() is public for testing only.
void LoadV1Drivers(std::string_view sys_device_driver,
fbl::Vector<std::string>& driver_search_paths,
fbl::Vector<const char*>& load_drivers);
void InitCoreDevices(std::string_view sys_device_driver);
void DriverAddedInit(Driver* drv, const char* version);
// Start searching the system for non-boot drivers.
// This will start a new thread to load non-boot drivers asynchronously.
void StartLoadingNonBootDrivers();
void BindFallbackDrivers();
void AddAndBindDrivers(fbl::DoublyLinkedList<std::unique_ptr<Driver>> drivers);
zx_status_t BindDriverToDeviceGroup(const MatchedDriver& driver, const fbl::RefPtr<Device>& dev);
void DriverAdded(Driver* drv, const char* version);
zx_status_t AddDeviceGroup(const fbl::RefPtr<Device>& dev, std::string_view name,
fuchsia_device_manager::wire::DeviceGroupDescriptor group_desc);
zx_status_t LibnameToVmo(const fbl::String& libname, zx::vmo* out_vmo) const;
const Driver* LibnameToDriver(std::string_view libname) const;
zx_status_t MakeVisible(const fbl::RefPtr<Device>& dev);
static zx_status_t GetTopologicalPath(const fbl::RefPtr<const Device>& dev, char* out,
size_t max);
zx_status_t GetMetadata(const fbl::RefPtr<Device>& dev, uint32_t type, void* buffer,
size_t buflen, size_t* size);
zx_status_t GetMetadataSize(const fbl::RefPtr<Device>& dev, uint32_t type, size_t* size) {
return GetMetadata(dev, type, nullptr, 0, size);
}
zx_status_t AddMetadata(const fbl::RefPtr<Device>& dev, uint32_t type, const void* data,
uint32_t length);
zx_status_t PrepareProxy(const fbl::RefPtr<Device>& dev,
fbl::RefPtr<DriverHost> target_driver_host);
zx_status_t PrepareNewProxy(const fbl::RefPtr<Device>& dev,
fbl::RefPtr<DriverHost> target_driver_host);
async_dispatcher_t* dispatcher() const { return dispatcher_; }
const zx::resource& root_resource() const { return config_.root_resource; }
zx::duration resume_timeout() const { return config_.resume_timeout; }
fidl::WireSyncClient<fuchsia_boot::Arguments>* boot_args() const { return config_.boot_args; }
SystemPowerState shutdown_system_state() const { return shutdown_system_state_; }
SystemPowerState default_shutdown_system_state() const {
return config_.default_shutdown_system_state;
}
void set_shutdown_system_state(SystemPowerState state) { shutdown_system_state_ = state; }
void set_running(bool running) { running_ = running; }
void set_power_manager_registered(bool registered) { power_manager_registered_ = registered; }
bool power_manager_registered() { return power_manager_registered_; }
void set_loader_service_connector(LoaderServiceConnector loader_service_connector) {
loader_service_connector_ = std::move(loader_service_connector);
}
void set_system_state_manager(std::unique_ptr<SystemStateManager> system_state_mgr) {
system_state_manager_ = std::move(system_state_mgr);
}
fbl::DoublyLinkedList<std::unique_ptr<Driver>>& drivers() { return drivers_; }
const fbl::DoublyLinkedList<std::unique_ptr<Driver>>& drivers() const { return drivers_; }
// Called when a new driver becomes available to the Coordinator. Existing devices are
// inspected to see if the new driver is bindable to them (unless they are already bound).
// This method is public only for the test suite.
zx_status_t BindDriver(Driver* drv);
// Callback function to attempt binding a driver to the device.
// TODO(fxb/90932): Remove this callback, as it makes things more complex and is only useful
// for testing.
zx_status_t AttemptBind(const Driver* drv, const fbl::RefPtr<Device>& dev);
// This method is public only for the LoadDriverPackageTest.
zx_status_t LoadEphemeralDriver(internal::PackageResolverInterface* resolver,
const std::string& package_url);
// These methods are used by the DriverHost class to register in the coordinator's bookkeeping
void RegisterDriverHost(DriverHost* dh) { driver_hosts_.push_back(dh); }
void UnregisterDriverHost(DriverHost* dh) { driver_hosts_.erase(*dh); }
// Returns URL to driver that should be bound to fragments of composite devices.
std::string GetFragmentDriverUrl() const;
using RegisterWithPowerManagerCompletion = fit::callback<void(zx_status_t)>;
void RegisterWithPowerManager(fidl::ClientEnd<fuchsia_io::Directory> devfs,
RegisterWithPowerManagerCompletion completion);
void RegisterWithPowerManager(
fidl::ClientEnd<fuchsia_power_manager::DriverManagerRegistration> power_manager,
fidl::ClientEnd<fuchsia_device_manager::SystemStateTransition> system_state_transition,
fidl::ClientEnd<fuchsia_io::Directory> devfs, RegisterWithPowerManagerCompletion completion);
const fbl::RefPtr<Device>& root_device() { return root_device_; }
const fbl::RefPtr<Device>& sys_device() { return sys_device_; }
zx_status_t SetMexecZbis(zx::vmo kernel_zbi, zx::vmo data_zbi);
SuspendResumeManager* suspend_resume_manager() { return suspend_resume_manager_.get(); }
const Driver* fragment_driver() { return driver_loader_.LoadDriverUrl(GetFragmentDriverUrl()); }
InspectManager& inspect_manager() { return *inspect_manager_; }
DriverLoader& driver_loader() { return driver_loader_; }
DeviceManager* device_manager() const { return device_manager_.get(); }
BindDriverManager* bind_driver_manager() const { return bind_driver_manager_.get(); }
FirmwareLoader* firmware_loader() const { return firmware_loader_.get(); }
// Only exposed for testing.
const DebugDump* debug_dump() const { return debug_dump_.get(); }
zx::vmo& mexec_kernel_zbi() { return mexec_kernel_zbi_; }
zx::vmo& mexec_data_zbi() { return mexec_data_zbi_; }
private:
// fuchsia.driver.development/DriverDevelopment interface
void RestartDriverHosts(RestartDriverHostsRequestView request,
RestartDriverHostsCompleter::Sync& completer) override;
void GetDriverInfo(GetDriverInfoRequestView request,
GetDriverInfoCompleter::Sync& completer) override;
void GetDeviceInfo(GetDeviceInfoRequestView request,
GetDeviceInfoCompleter::Sync& completer) override;
void BindAllUnboundNodes(BindAllUnboundNodesRequestView request,
BindAllUnboundNodesCompleter::Sync& completer) override;
// fuchsia.device.manager/Administrator interface
void UnregisterSystemStorageForShutdown(
UnregisterSystemStorageForShutdownRequestView request,
UnregisterSystemStorageForShutdownCompleter::Sync& completer) override;
// Driver registrar interface
void Register(RegisterRequestView request, RegisterCompleter::Sync& completer) override;
zx_status_t NewDriverHost(const char* name, fbl::RefPtr<DriverHost>* out);
CoordinatorConfig config_;
async_dispatcher_t* const dispatcher_;
bool running_ = false;
bool launched_first_driver_host_ = false;
bool power_manager_registered_ = false;
LoaderServiceConnector loader_service_connector_;
fidl::WireSharedClient<fuchsia_power_manager::DriverManagerRegistration> power_manager_client_;
internal::BasePackageResolver base_resolver_;
// All Drivers
fbl::DoublyLinkedList<std::unique_ptr<Driver>> drivers_;
// Drivers to try last
fbl::DoublyLinkedList<std::unique_ptr<Driver>> fallback_drivers_;
// All DriverHosts
fbl::DoublyLinkedList<DriverHost*> driver_hosts_;
fbl::RefPtr<Device> root_device_;
fbl::RefPtr<Device> sys_device_;
InspectManager* const inspect_manager_;
std::unique_ptr<SystemStateManager> system_state_manager_;
SystemPowerState shutdown_system_state_;
cpp17::optional<fidl::ServerBindingRef<fuchsia_driver_registrar::DriverRegistrar>>
driver_registrar_binding_;
internal::PackageResolver package_resolver_;
DriverLoader driver_loader_;
std::unique_ptr<DebugDump> debug_dump_;
std::unique_ptr<FirmwareLoader> firmware_loader_;
// Stashed mexec inputs.
zx::vmo mexec_kernel_zbi_, mexec_data_zbi_;
std::unique_ptr<SuspendResumeManager> suspend_resume_manager_;
std::unique_ptr<DeviceManager> device_manager_;
std::unique_ptr<BindDriverManager> bind_driver_manager_;
};
#endif // SRC_DEVICES_BIN_DRIVER_MANAGER_COORDINATOR_H_