blob: 345e07a9896f35f170d0bcb477d5f2b2a7fcf7a9 [file] [log] [blame]
// Copyright 2016 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 <fidl/fuchsia.boot/cpp/wire.h>
#include <fidl/fuchsia.driver.index/cpp/wire.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/component/incoming/cpp/protocol.h>
#include <lib/component/outgoing/cpp/outgoing_directory.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/io.h>
#include <lib/zx/event.h>
#include <lib/zx/port.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <threads.h>
#include <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <zircon/syscalls/policy.h>
#include <zircon/types.h>
#include <cstdlib>
#include <cstring>
#include <limits>
#include <memory>
#include <fbl/unique_fd.h>
#include "src/devices/bin/driver_manager/devfs/devfs.h"
#include "src/devices/bin/driver_manager/driver_development_service.h"
#include "src/devices/bin/driver_manager/driver_host_loader_service.h"
#include "src/devices/bin/driver_manager/driver_manager_config.h"
#include "src/devices/bin/driver_manager/driver_runner.h"
#include "src/devices/bin/driver_manager/shutdown_manager.h"
#include "src/devices/lib/log/log.h"
#include "src/storage/lib/vfs/cpp/synchronous_vfs.h"
#include "src/sys/lib/stdout-to-debuglog/cpp/stdout-to-debuglog.h"
namespace fio = fuchsia_io;
namespace {
// Sets the logging process name. Needed to redirect output
// to serial.
void SetLoggingProcessName() {
char process_name[ZX_MAX_NAME_LEN] = "";
zx_status_t name_status =
zx::process::self()->get_property(ZX_PROP_NAME, process_name, sizeof(process_name));
if (name_status != ZX_OK) {
process_name[0] = '\0';
}
driver_logger::GetLogger().AddTag(process_name);
}
} // namespace
int main(int argc, char** argv) {
zx_status_t status = StdoutToDebuglog::Init();
if (status != ZX_OK) {
LOGF(INFO, "Failed to redirect stdout to debuglog, assuming test environment and continuing");
}
auto config = driver_manager_config::Config::TakeFromStartupHandle();
if (config.verbose()) {
driver_logger::GetLogger().SetSeverity(std::numeric_limits<FuchsiaLogSeverity>::min());
}
SetLoggingProcessName();
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
auto outgoing = component::OutgoingDirectory(loop.dispatcher());
driver_manager::InspectManager inspect_manager(loop.dispatcher());
// Launch DriverRunner for DFv2 drivers.
auto realm_result = component::Connect<fuchsia_component::Realm>();
if (realm_result.is_error()) {
return realm_result.error_value();
}
auto driver_index_result = component::Connect<fuchsia_driver_index::DriverIndex>();
if (driver_index_result.is_error()) {
LOGF(ERROR, "Failed to connect to driver_index: %d", driver_index_result.error_value());
return driver_index_result.error_value();
}
fbl::unique_fd lib_fd;
constexpr uint32_t kOpenFlags = static_cast<uint32_t>(fio::wire::OpenFlags::kDirectory |
fio::wire::OpenFlags::kRightReadable |
fio::wire::OpenFlags::kRightExecutable);
if (zx_status_t status = fdio_open_fd("/pkg/lib/", kOpenFlags, lib_fd.reset_and_get_address());
status != ZX_OK) {
LOGF(ERROR, "Failed to open /pkg/lib/ : %s", zx_status_get_string(status));
return status;
}
// The loader needs its own thread because DriverManager makes synchronous calls to the
// DriverHosts, which make synchronous calls to load their shared libraries.
async::Loop loader_loop(&kAsyncLoopConfigNoAttachToCurrentThread);
loader_loop.StartThread("loader-loop");
auto loader_service =
driver_manager::DriverHostLoaderService::Create(loader_loop.dispatcher(), std::move(lib_fd));
driver_manager::DriverRunner driver_runner(
std::move(realm_result.value()), std::move(driver_index_result.value()), inspect_manager,
[loader_service]() -> zx::result<fidl::ClientEnd<fuchsia_ldsvc::Loader>> {
zx::result client = loader_service->Connect();
if (client.is_error()) {
return client.take_error();
}
// TODO(https://fxbug.dev/42076026): Find a better way to set this config.
#ifdef DRIVERHOST_LDSVC_CONFIG
// Inform the loader service to look for libraries of the right variant.
fidl::WireResult result = fidl::WireCall(client.value())->Config(DRIVERHOST_LDSVC_CONFIG);
if (!result.ok()) {
return zx::error(result.status());
}
if (result->rv != ZX_OK) {
return zx::error(result->rv);
}
#endif
return client;
},
loop.dispatcher(), config.enable_test_shutdown_delays());
// Setup devfs.
std::optional<driver_manager::Devfs> devfs;
driver_runner.root_node()->SetupDevfsForRootNode(devfs);
driver_runner.PublishComponentRunner(outgoing);
// Find and load v2 Drivers.
LOGF(INFO, "Starting DriverRunner with root driver URL: %s", config.root_driver().c_str());
if (auto start = driver_runner.StartRootDriver(config.root_driver()); start.is_error()) {
return start.error_value();
}
driver_manager::DriverDevelopmentService driver_development_service(driver_runner,
loop.dispatcher());
driver_development_service.Publish(outgoing);
driver_runner.ScheduleWatchForDriverLoad();
driver_manager::ShutdownManager shutdown_manager(&driver_runner, loop.dispatcher());
shutdown_manager.Publish(outgoing);
// TODO(https://fxbug.dev/42181480) Remove this when this issue is fixed.
LOGF(INFO, "driver_manager loader loop started");
fs::SynchronousVfs vfs(loop.dispatcher());
// Add the devfs folder to the tree:
{
zx::result devfs_client = devfs.value().Connect(vfs);
ZX_ASSERT_MSG(devfs_client.is_ok(), "%s", devfs_client.status_string());
const zx::result result = outgoing.AddDirectory(std::move(devfs_client.value()), "dev");
ZX_ASSERT(result.is_ok());
}
{
const zx::result result = outgoing.ServeFromStartupInfo();
ZX_ASSERT_MSG(result.is_ok(), "%s", result.status_string());
}
async::PostTask(loop.dispatcher(), [] { LOGF(INFO, "driver_manager main loop is running"); });
status = loop.Run();
LOGF(ERROR, "Driver Manager exited unexpectedly: %s", zx_status_get_string(status));
return status;
}