blob: c4cbf688cefa059b4ba02c7304400ed6b6f9226c [file] [log] [blame]
// Copyright 2018 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 LIB_DEVMGR_INTEGRATION_TEST_FIXTURE_H_
#define LIB_DEVMGR_INTEGRATION_TEST_FIXTURE_H_
#include <fuchsia/io/llcpp/fidl.h>
#include <fuchsia/process/lifecycle/llcpp/fidl.h>
#include <lib/async/dispatcher.h>
#include <lib/devmgr-launcher/launch.h>
#include <lib/fit/function.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/zx/job.h>
#include <lib/zx/time.h>
#include <fbl/string.h>
#include <fbl/unique_fd.h>
namespace devmgr_integration_test {
class IsolatedDevmgr {
public:
IsolatedDevmgr();
~IsolatedDevmgr();
IsolatedDevmgr(const IsolatedDevmgr&) = delete;
IsolatedDevmgr& operator=(const IsolatedDevmgr&) = delete;
IsolatedDevmgr(IsolatedDevmgr&& other);
IsolatedDevmgr& operator=(IsolatedDevmgr&& other);
// Path to the test sysdev driver
static inline constexpr char kSysdevDriver[] = "/boot/driver/test/sysdev.so";
// Get an args structure pre-populated with the test sysdev driver, the
// test control driver, and the test driver directory.
static devmgr_launcher::Args DefaultArgs();
// Launch a new isolated devmgr. The instance will be destroyed when
// |*out|'s dtor runs.
// |dispatcher| let's you choose which async loop the exception handler runs on.
static zx_status_t Create(devmgr_launcher::Args args, IsolatedDevmgr* out);
static zx_status_t Create(devmgr_launcher::Args args, async_dispatcher_t* dispatcher,
IsolatedDevmgr* out);
// Get a fd to the root of the isolate devmgr's devfs. This fd
// may be used with openat() and fdio_watch_directory().
const fbl::unique_fd& devfs_root() const { return devfs_root_; }
fidl::UnownedClientEnd<fuchsia_io::Directory> svc_root_dir() const { return svc_root_dir_; }
fidl::UnownedClientEnd<fuchsia_io::Directory> fshost_outgoing_dir() const {
return fshost_outgoing_dir_;
}
fidl::UnownedClientEnd<fuchsia_process_lifecycle::Lifecycle> component_lifecycle_svc() const {
return component_lifecycle_client_;
}
fidl::ClientEnd<fuchsia_io::Directory> TakeSvcRootDir() { return std::move(svc_root_dir_); }
// Expose devfs in component outgoing directory.
zx_status_t AddDevfsToOutgoingDir(vfs::PseudoDir* outgoing_root_dir);
// Notifies if driver manager job has an exception.
void SetExceptionCallback(fit::closure exception_callback);
// Returns true if any process in driver manager process crashes.
bool crashed() const;
// Borrow the handle to the job containing the isolated devmgr. This may be
// used for things like binding to an exception port.
const zx::job& containing_job() const { return job_; }
void reset() { *this = IsolatedDevmgr(); }
private:
using GetBootItemFunction = devmgr_launcher::GetBootItemFunction;
// Opaque structure for the internal state used for serving /svc
struct SvcLoopState;
zx_status_t SetupSvcLoop(fidl::ServerEnd<fuchsia_io::Directory> bootsvc_server,
fidl::ClientEnd<fuchsia_io::Directory> fshost_outgoing_client,
GetBootItemFunction get_boot_item,
std::map<std::string, std::string>&& boot_args);
struct ExceptionLoopState;
zx_status_t SetupExceptionLoop(async_dispatcher_t* dispatcher, zx::channel exception_channel);
// If |job_| exists, terminate it.
void Terminate();
// Job that contains the devmgr environment
zx::job job_;
// Channel for the root of outgoing services
fidl::ClientEnd<fuchsia_io::Directory> svc_root_dir_;
// Channel for the root of fshost
fidl::ClientEnd<fuchsia_io::Directory> fshost_outgoing_dir_;
// FD to the root of devmgr's devfs
fbl::unique_fd devfs_root_;
// Channel for component lifecycle events
fidl::ClientEnd<fuchsia_process_lifecycle::Lifecycle> component_lifecycle_client_;
// Opaque state associated with the async_loop_
std::unique_ptr<SvcLoopState> svc_loop_state_;
// Opaque state associated with the async_loop_
std::unique_ptr<ExceptionLoopState> exception_loop_state_;
};
// Wait for |file| to appear in |dir|, and open it when it does.
zx_status_t WaitForFile(const fbl::unique_fd& dir, const char* file, fbl::unique_fd* out);
// Waits for the relative |path| starting in |dir| to appear, and opens it.
zx_status_t RecursiveWaitForFile(const fbl::unique_fd& dir, const char* path, fbl::unique_fd* out);
// Waits for the relative |path| starting in |dir| to appear, and opens it in Read only mode.
zx_status_t RecursiveWaitForFileReadOnly(const fbl::unique_fd& dir, const char* path,
fbl::unique_fd* out);
// DirWatcher can be used to detect when a file has been removed from the filesystem.
//
// Example usage:
//
// std::unique_ptr<DirWatcher> watcher;
// zx_status_t status = DirWatcher::Create(dir_fd, &watcher);
// ...
// // Trigger removal of file here.
// ...
// status = watcher->WaitForRemoval(filename, deadline);
class DirWatcher {
public:
// |dir_fd| is the directory to watch.
static zx_status_t Create(fbl::unique_fd dir_fd, std::unique_ptr<DirWatcher>* out_dir_watcher);
// Users should call Create instead. This is public for make_unique.
explicit DirWatcher(zx::channel client) : client_(std::move(client)) {}
// Returns ZX_OK if |filename| is removed from the directory before the given timeout elapses.
// If no filename is specified, this will wait for any file in the directory to be removed.
zx_status_t WaitForRemoval(const fbl::String& filename, zx::duration timeout);
private:
zx::channel client_;
};
} // namespace devmgr_integration_test
#endif // LIB_DEVMGR_INTEGRATION_TEST_FIXTURE_H_