blob: b714cd6f25716b5b2ec24c418e729e6bec2b7310 [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_LIB_LOADER_SERVICE_LOADER_SERVICE_H_
#define SRC_LIB_LOADER_SERVICE_LOADER_SERVICE_H_
#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> {
public:
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();
protected:
LoaderServiceBase(async_dispatcher_t* dispatcher, std::string name)
: dispatcher_(dispatcher), name_(std::move(name)) {}
private:
// 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("libfoo.so")` call will result in the base class calling this with
// "asan/libfoo.so".
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;
DISALLOW_COPY_ASSIGN_AND_MOVE(LoaderServiceBase);
};
// 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::WireInterface<fuchsia_ldsvc::Loader> {
public:
LoaderConnection(std::shared_ptr<LoaderServiceBase> server) : server_(server) {}
// fidl::WireInterface<fuchsia_ldsvc::Loader> 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(fidl::ServerEnd<fuchsia_ldsvc::Loader> loader,
CloneCompleter::Sync& completer) override;
private:
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_;
DISALLOW_COPY_ASSIGN_AND_MOVE(LoaderConnection);
};
// 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 {
public:
// 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);
protected:
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;
private:
fbl::unique_fd dir_;
};
} // namespace loader
#endif // SRC_LIB_LOADER_SERVICE_LOADER_SERVICE_H_