blob: 3770eda5304859030a0150e7cde8c950a21ef305 [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.
#include <fuchsia/ldsvc/llcpp/fidl.h>
#include <lib/async/dispatcher.h>
#include <lib/zx/channel.h>
#include <lib/zx/status.h>
#include <lib/zx/vmo.h>
#include <zircon/types.h>
#include <memory>
#include <fbl/macros.h>
#include <fbl/unique_fd.h>
namespace loader {
// Pure virtual base class for a fuchsia.ldsvc.Loader FIDL server. See concrete LoaderService
// implementation below, which should fit most use cases, or subclass to customize the behavior of
// LoadObjectImpl for your use case.
// Connections to the loader service stay alive as long as the client keeps the connection open (and
// other obvious things, like the async dispatcher is not shutdown and the hosting process is
// alive), even if the creator of the service drops any copies of this object.
class LoaderServiceBase : public std::enable_shared_from_this<LoaderServiceBase> {
virtual ~LoaderServiceBase();
// Bind and Connect create a new connection to the loader service. Connect is identical to
// Bind but creates the channel for the caller.
zx::status<> Bind(zx::channel channel);
zx::status<zx::channel> Connect();
LoaderServiceBase(async_dispatcher_t* dispatcher, std::string name)
: dispatcher_(dispatcher), name_(std::move(name)) {}
// Pure virtual methods to be implemented by subclasses.
// LoadObjectImpl shall return a VMO with the contents of the specified path. The interpretation
// of the path is defined by the concrete subclass; it may simply open the path from a given
// directory, or may do something more complex.
// The returned VMO shall have the ZX_RIGHT_EXECUTE right, i.e. the file must be opened executable
// or this call shall fail with ZX_ERR_ACCESS_DENIED if the file cannot be opened executable.
// The path parameter may contain one or more path components. The base class handles applying
// loader config as requested by the client. For example, a `Config("asan!")` call followed by a
// `LoadObject("")` call will result in the base class calling this with
// "asan/".
virtual zx::status<zx::vmo> LoadObjectImpl(std::string path) = 0;
const std::string& log_prefix();
async_dispatcher_t* dispatcher_;
// This name is only used when logging to provide useful context for which loader service is
// logging, since processes which host loaders sometimes host many of them.
std::string name_;
std::string log_prefix_;
friend class LoaderConnection;
// Represents a single client connection to the loader service, including per-connection state. Used
// internally by LoaderServiceBase and not intended to be used directly.
// Connections have a strong reference to the server object (through std::shared_ptr), which keeps
// the loader service alive as long as any open client connections exist.
class LoaderConnection : public llcpp::fuchsia::ldsvc::Loader::RawChannelInterface {
LoaderConnection(std::shared_ptr<LoaderServiceBase> server) : server_(server) {}
// llcpp::fuchsia::ldsvc::Loader::Interface implementation
virtual void Done(DoneCompleter::Sync& completer) override;
virtual void LoadObject(fidl::StringView object_name,
LoadObjectCompleter::Sync& completer) override;
virtual void Config(fidl::StringView config, ConfigCompleter::Sync& completer) override;
virtual void Clone(zx::channel loader, CloneCompleter::Sync& completer) override;
const std::string& log_prefix() { return server_->log_prefix(); }
// Wraps loader configuration set through the fuchsia.ldsvc.Loader.Config FIDL method.
struct LoadConfig {
std::string subdir;
bool exclusive;
std::shared_ptr<LoaderServiceBase> server_;
LoadConfig config_;
// Concrete implementation of a fuchsia.ldsvc.Loader FIDL server that serves libraries from a single
// directory, e.g. from a component's specific "/pkg/lib/" directory.
class LoaderService : public LoaderServiceBase {
// This takes ownership of the 'lib_dir` fd and will close it automatically once all connections
// to the loader service are closed and copies of this object are destroyed. `name` is used to
// provide context when logging.
static std::shared_ptr<LoaderService> Create(async_dispatcher_t* dispatcher,
fbl::unique_fd lib_dir, std::string name);
LoaderService(async_dispatcher_t* dispatcher, fbl::unique_fd lib_dir, std::string name)
: LoaderServiceBase(dispatcher, std::move(name)), dir_(std::move(lib_dir)) {}
virtual zx::status<zx::vmo> LoadObjectImpl(std::string path) override;
fbl::unique_fd dir_;
} // namespace loader