blob: ba6cca9b0e913d10a737f94d13288f928c1a6c5d [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.
#ifndef SRC_SYS_APPMGR_REALM_H_
#define SRC_SYS_APPMGR_REALM_H_
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/sys/internal/cpp/fidl.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fit/function.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/zx/channel.h>
#include <lib/zx/status.h>
#include <zircon/syscalls/policy.h>
#include <zircon/types.h>
#include <iosfwd>
#include <memory>
#include <string>
#include <unordered_map>
#include <fbl/unique_fd.h>
#include "garnet/lib/loader/package_loader.h"
#include "src/lib/cmx/runtime.h"
#include "src/lib/fsl/vmo/file.h"
#include "src/lib/fxl/macros.h"
#include "src/lib/fxl/memory/ref_ptr.h"
#include "src/lib/fxl/memory/weak_ptr.h"
#include "src/lib/storage/vfs/cpp/synchronous_vfs.h"
#include "src/sys/appmgr/cache_control.h"
#include "src/sys/appmgr/component_container.h"
#include "src/sys/appmgr/component_controller_impl.h"
#include "src/sys/appmgr/component_event_provider_impl.h"
#include "src/sys/appmgr/component_id_index.h"
#include "src/sys/appmgr/cpu_watcher.h"
#include "src/sys/appmgr/crash_introspector.h"
#include "src/sys/appmgr/environment_controller_impl.h"
#include "src/sys/appmgr/hub/hub_info.h"
#include "src/sys/appmgr/hub/realm_hub.h"
#include "src/sys/appmgr/log_connector_impl.h"
#include "src/sys/appmgr/moniker.h"
#include "src/sys/appmgr/namespace.h"
#include "src/sys/appmgr/namespace_builder.h"
#include "src/sys/appmgr/runner_holder.h"
#include "src/sys/appmgr/scheme_map.h"
namespace component {
class ComponentEventProviderImpl;
namespace internal {
constexpr char kRootLabel[] = "app";
// When a component event will be triggered, this struct will contain what provider to notify and
// with which component identity data.
struct EventNotificationInfo {
ComponentEventProviderImpl* provider;
fuchsia::sys::internal::SourceIdentity component;
};
enum class StorageType { DATA, CACHE, TEMP };
} // namespace internal
struct RealmArgs {
static RealmArgs Make(fxl::WeakPtr<Realm> parent, std::string label, std::string data_path,
std::string cache_path, std::string temp_path,
const std::shared_ptr<sys::ServiceDirectory>& env_services,
bool run_virtual_console, fuchsia::sys::EnvironmentOptions options,
fbl::unique_fd appmgr_config_dir,
fbl::RefPtr<ComponentIdIndex> component_id_index);
static RealmArgs MakeWithAdditionalServices(
fxl::WeakPtr<Realm> parent, std::string label, std::string data_path, std::string cache_path,
std::string temp_path, const std::shared_ptr<sys::ServiceDirectory>& env_services,
bool run_virtual_console, fuchsia::sys::ServiceListPtr additional_services,
fuchsia::sys::EnvironmentOptions options, fbl::unique_fd appmgr_config_dir,
fbl::RefPtr<ComponentIdIndex> component_id_index);
static RealmArgs MakeWithCustomLoader(
fxl::WeakPtr<Realm> parent, std::string label, std::string data_path, std::string cache_path,
std::string temp_path, const std::shared_ptr<sys::ServiceDirectory>& env_services,
bool run_virtual_console, fuchsia::sys::ServiceListPtr additional_services,
fuchsia::sys::EnvironmentOptions options, fbl::unique_fd appmgr_config_dir,
fbl::RefPtr<ComponentIdIndex> component_id_index, fuchsia::sys::LoaderPtr loader);
fxl::WeakPtr<Realm> parent;
std::string label;
std::string data_path;
std::string cache_path;
std::string temp_path;
std::shared_ptr<sys::ServiceDirectory> environment_services;
bool run_virtual_console;
fuchsia::sys::ServiceListPtr additional_services;
fuchsia::sys::EnvironmentOptions options;
fbl::unique_fd appmgr_config_dir;
CpuWatcher* cpu_watcher;
fbl::RefPtr<ComponentIdIndex> component_id_index;
std::optional<fuchsia::sys::LoaderPtr> loader;
};
class Realm : public ComponentContainer<ComponentControllerImpl> {
public:
using ShutdownNamespaceCallback = fit::callback<void()>;
static std::unique_ptr<Realm> Create(RealmArgs args);
// Constructor to create a Realm object. Clients should call |Create|.
Realm(RealmArgs args, zx::job job);
~Realm();
fxl::WeakPtr<Realm> parent() const { return parent_; }
CpuWatcher* cpu_watcher() const { return cpu_watcher_; }
const std::string& label() const { return label_; }
const std::string& data_path() const { return data_path_; }
const std::string& cache_path() const { return cache_path_; }
const std::string& temp_path() const { return temp_path_; }
const std::string& koid() const { return koid_; }
const fbl::RefPtr<LogConnectorImpl>& log_connector() const { return log_connector_; }
const fbl::RefPtr<fs::PseudoDir>& hub_dir() const { return hub_.dir(); }
std::shared_ptr<sys::ServiceDirectory> environment_services() const {
return environment_services_;
}
HubInfo HubInfo();
zx::job DuplicateJobForHub() const;
const zx::job& job() const { return job_; }
const std::unordered_map<ComponentControllerImpl*, std::shared_ptr<ComponentControllerImpl>>&
applications() const {
return applications_;
}
const std::unordered_map<std::string, std::unique_ptr<RunnerHolder>>& runners() const {
return runners_;
}
const std::unordered_map<Realm*, std::unique_ptr<EnvironmentControllerImpl>>& children() const {
return children_;
}
fxl::WeakPtr<Realm> weak_ptr() { return weak_ptr_factory_.GetWeakPtr(); }
void CreateNestedEnvironment(
fidl::InterfaceRequest<fuchsia::sys::Environment> environment,
fidl::InterfaceRequest<fuchsia::sys::EnvironmentController> controller_request,
std::string label, fuchsia::sys::ServiceListPtr additional_services,
fuchsia::sys::EnvironmentOptions options);
using ComponentObjectCreatedCallback =
fit::function<void(std::weak_ptr<ComponentControllerImpl> component)>;
void CreateComponent(fuchsia::sys::LaunchInfo launch_info,
fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller,
ComponentObjectCreatedCallback callback = nullptr);
// Removes the child realm from this realm and returns the owning
// reference to the child's controller. The caller of this function
// typically destroys the controller (and hence the environment) shortly
// after calling this function.
std::unique_ptr<EnvironmentControllerImpl> ExtractChild(Realm* child);
// Removes the application from this environment and returns the owning
// reference to the application's controller. The caller of this function
// typically destroys the controller (and hence the application) shortly after
// calling this function.
// We use shared_ptr so that we can pass weak_ptrs to dependent code.
std::shared_ptr<ComponentControllerImpl> ExtractComponent(
ComponentControllerImpl* controller) override;
void AddBinding(fidl::InterfaceRequest<fuchsia::sys::Environment> environment);
// Binds the given channel to the services directory (/svc) for the very first
// nested realm created. This function is only supported for the root realm,
// otherwise it will do nothing and return ZX_ERR_NOT_SUPPORTED.
zx_status_t BindFirstNestedRealmSvc(zx::channel channel);
void CreateShell(const std::string& path, zx::channel svc);
void Resolve(fidl::StringPtr name, fuchsia::process::Resolver::ResolveCallback callback);
// Notifies the |ComponentEventListener| of this realm or the closest parent realm (if there's
// one) with a component out/diagnostics directory when the directory is available.
void NotifyComponentDiagnosticsDirReady(const std::string& component_url,
const std::string& component_name,
const std::string& instance_id,
fidl::InterfaceHandle<fuchsia::io::Directory> directory);
// Notifies the Realm components event subscriber when a component starts.
void NotifyComponentStarted(const std::string& component_url, const std::string& component_name,
const std::string& instance_id);
// Notifies the Realm components event subscriber when a component stops.
void NotifyComponentStopped(const std::string& component_url, const std::string& component_name,
const std::string& instance_id);
// Creates a connection to |fuchsia::sys::internal::ComponentEventProvider|.
zx_status_t BindComponentEventProvider(
fidl::InterfaceRequest<fuchsia::sys::internal::ComponentEventProvider> request);
// Whether a `ComponentEventListener` has been bound to this realm `ComponentEventProvider`.
bool HasComponentEventListenerBound();
// Given a component url |fp|, initializes and returns the component's absolute storage
// directory for the given |storage_path|. Returns an error if the directory could not be made.
//
// A component instance's storage directory is in one of two places:
// (a) A directory keyed using component instance ID, if it has one.
// (b) A directory computed using fn(realm_path, component URL)
//
// If a component is assigned an instance ID while it already has a storage
// directory under (b), its storage directory is moved to (a).
//
// Note: This method is public only for the purposes for testing storage paths and migration
// logic.
fpromise::result<std::string, zx_status_t> InitIsolatedPathForComponentInstance(
const FuchsiaPkgUrl& fp, internal::StorageType storage_type);
// Shutdown realm's namespace processing all pending messages.
void ShutdownNamespace(ShutdownNamespaceCallback callback = nullptr);
static Moniker ComputeMoniker(Realm* realm, const FuchsiaPkgUrl& fp);
private:
static uint32_t next_numbered_label_;
// Returns |runner| if it exists in |runners_|, otherwise creates a runner in
// |runners_|. If |use_parent_runners_| is true, creates |runner| in
// |parent_->runners_|.
RunnerHolder* GetOrCreateRunner(const std::string& runner);
Realm* GetRunnerRealm();
void CreateComponentWithRunnerForScheme(std::string runner_url,
fuchsia::sys::LaunchInfo launch_info,
ComponentRequestWrapper component_request,
ComponentObjectCreatedCallback callback);
void CreateComponentFromPackage(fuchsia::sys::PackagePtr package,
fuchsia::sys::LaunchInfo launch_info,
ComponentRequestWrapper component_request,
ComponentObjectCreatedCallback callback);
void CreateElfBinaryComponentFromPackage(
fuchsia::sys::LaunchInfo launch_info, zx::vmo executable, const std::string& app_argv0,
std::vector<std::string> env_vars, zx::channel loader_service, fdio_flat_namespace_t* flat,
ComponentRequestWrapper component_request, fxl::RefPtr<Namespace> ns,
const std::vector<zx_policy_basic_v2_t>& policies, ComponentObjectCreatedCallback callback,
zx::channel package_handle);
void CreateRunnerComponentFromPackage(
fuchsia::sys::PackagePtr package, fuchsia::sys::LaunchInfo launch_info,
RuntimeMetadata& runtime, fuchsia::sys::FlatNamespace flat,
ComponentRequestWrapper component_request, fxl::RefPtr<Namespace> ns,
fidl::VectorPtr<fuchsia::sys::ProgramMetadata> program_metadata, zx::channel package_handle);
// When a component event will be triggered, this finds what provider to notify and with what
// identity data. The provider will be either the one attached to this component or some
// provider in an ancestor realm.
internal::EventNotificationInfo GetEventNotificationInfo(const std::string& component_url,
const std::string& component_name,
const std::string& instance_id);
zx::channel OpenInfoDir();
// Called by `FindComponent`. This function returns realm path in reverse order.
zx::status<fuchsia::sys::internal::SourceIdentity> FindComponentInternal(zx_koid_t process_koid);
// Registers a job for crash introspection.
// This internally adds realm label to passed |component_info| and calls either it's own parent
// or directly calls introspector if this is a root realm.
void RegisterJobForCrashIntrospection(const zx::job& job,
fuchsia::sys::internal::SourceIdentity component_info);
fxl::WeakPtr<Realm> const parent_;
fuchsia::sys::LoaderPtr loader_;
std::string label_;
std::string data_path_;
std::string cache_path_;
std::string temp_path_;
std::string koid_;
std::vector<std::string> realm_path_;
const bool run_virtual_console_;
std::unique_ptr<component::PackageLoader> package_loader_;
std::unique_ptr<component::CacheControl> cache_control_;
fbl::RefPtr<LogConnectorImpl> log_connector_;
zx::job job_;
fxl::RefPtr<Namespace> default_namespace_;
std::unique_ptr<component::ComponentEventProviderImpl> component_event_provider_;
RealmHub hub_;
fs::SynchronousVfs info_vfs_;
std::unordered_map<Realm*, std::unique_ptr<EnvironmentControllerImpl>> children_;
std::unordered_map<ComponentControllerImpl*, std::shared_ptr<ComponentControllerImpl>>
applications_;
std::unordered_map<std::string, std::unique_ptr<RunnerHolder>> runners_;
// This channel pair is only created for the root realm, and is used to
// implement BindFirstNestedRealmSvc. The server end is used to serve the
// services directory (/svc) for the first nested realm created.
zx::channel first_nested_realm_svc_client_;
zx::channel first_nested_realm_svc_server_;
SchemeMap scheme_map_;
const std::shared_ptr<sys::ServiceDirectory> environment_services_;
fbl::unique_fd appmgr_config_dir_;
bool use_parent_runners_ = false;
bool delete_storage_on_death_ = false;
// Pointer to a cpu watcher to register and unregister components for sampling.
// Not owned.
CpuWatcher* const cpu_watcher_;
fbl::RefPtr<ComponentIdIndex> component_id_index_;
fxl::WeakPtrFactory<Realm> weak_ptr_factory_;
// Implement crash introspect service. Only initialized in root realm.
std::unique_ptr<CrashIntrospector> crash_introspector_;
// GWP-ASan configuration. If not empty, it is an environment variable (SCUDO_OPTIONS) that will
// be injected to all the ELF binary components.
std::string gwp_asan_config_;
FXL_DISALLOW_COPY_AND_ASSIGN(Realm);
};
} // namespace component
#endif // SRC_SYS_APPMGR_REALM_H_