blob: 9997ed689f62e7d6d7c408ab52b9ebbbe6f2c22d [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.
void Bind(fidl::ServerEnd<fuchsia_ldsvc::Loader> channel);
zx::status<fidl::ClientEnd<fuchsia_ldsvc::Loader>> 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 fidl::WireServer<fuchsia_ldsvc::Loader> {
LoaderConnection(std::shared_ptr<LoaderServiceBase> server) : server_(server) {}
// fidl::WireServer<fuchsia_ldsvc::Loader> implementation
void Done(DoneRequestView request, DoneCompleter::Sync& completer) override;
void LoadObject(LoadObjectRequestView request, LoadObjectCompleter::Sync& completer) override;
void Config(ConfigRequestView request, ConfigCompleter::Sync& completer) override;
void Clone(CloneRequestView request, 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