text: // 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_NAMESPACE_H_
  #define SRC_SYS_APPMGR_NAMESPACE_H_
  
  #include <fuchsia/process/cpp/fidl.h>
  #include <fuchsia/sys/cpp/fidl.h>
  
  #include <memory>
  #include <string>
  #include <unordered_map>
  #include <vector>
  
  #include "lib/fidl/cpp/binding_set.h"
  #include "src/lib/fxl/macros.h"
  #include "src/lib/fxl/memory/ref_counted.h"
  #include "src/lib/storage/vfs/cpp/managed_vfs.h"
  #include "src/sys/appmgr/job_provider_impl.h"
  #include "src/sys/appmgr/moniker.h"
  #include "src/sys/appmgr/service_provider_dir_impl.h"
  
  namespace component {
  class Realm;
  
  class Namespace : public fuchsia::sys::Environment,
                    public fuchsia::sys::Launcher,
                    public fuchsia::process::Resolver,
                    public fxl::RefCountedThreadSafe<Namespace> {
   public:
    const fbl::RefPtr<ServiceProviderDirImpl>& services() const { return services_; }
    const fbl::RefPtr<JobProviderImpl>& job_provider() { return job_provider_; }
    fxl::WeakPtr<Realm> realm() const { return realm_; }
  
    void AddBinding(fidl::InterfaceRequest<fuchsia::sys::Environment> environment);
  
    zx_status_t ServeServiceDirectory(zx::channel request);
  
    zx::channel OpenServicesAsDirectory();
  
    //
    // fuchsia::process::Resolver implementation:
    //
    void Resolve(std::string name, fuchsia::process::Resolver::ResolveCallback callback) override;
  
    //
    // fuchsia::sys::Environment implementation:
    //
  
    void CreateNestedEnvironment(
        fidl::InterfaceRequest<fuchsia::sys::Environment> environment,
        fidl::InterfaceRequest<fuchsia::sys::EnvironmentController> controller, std::string label,
        fuchsia::sys::ServiceListPtr additional_services,
        fuchsia::sys::EnvironmentOptions options) override;
  
    void GetLauncher(fidl::InterfaceRequest<fuchsia::sys::Launcher> launcher) override;
  
    void GetServices(fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) override;
  
    void GetDirectory(zx::channel directory_request) override {
      ServeServiceDirectory(std::move(directory_request));
    }
  
    void set_component_moniker(const Moniker& moniker) { services_->set_component_moniker(moniker); }
    void set_component_id(const std::string& id) { services_->set_component_id(id); }
  
    //
    // fuchsia::sys::Launcher implementation:
    //
  
    void CreateComponent(
        fuchsia::sys::LaunchInfo launch_info,
        fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) override;
  
    // Adds the service to the service directory if it's allowlisted.
    void MaybeAddComponentEventProvider();
  
    // Notifies a realms ComponentEventListener with the out/diagnostics directory for a component.
    void NotifyComponentDiagnosticsDirReady(const std::string& component_url,
                                            const std::string& component_name,
                                            const std::string& component_id,
                                            fidl::InterfaceHandle<fuchsia::io::Directory> directory);
  
    // Notifies a realms ComponentEventListener that a component started.
    void NotifyComponentStarted(const std::string& component_url, const std::string& component_name,
                                const std::string& component_id);
  
    // Notifies a realms ComponentEventListener that a component stopped.
    void NotifyComponentStopped(const std::string& component_url, const std::string& component_name,
                                const std::string& component_id);
  
    // Proccesses all pending messages and shuts downs children and self.
    // We handle shutdown here and not in realm and component as
    // 1. It is lot of work to get realm and component to maintain state and close all dependencies.
    // 2. Namespace doesn't need realm and component to be active so we can shut it down in
    // background.
    // 3. We anyways need to do this as a namespace might be dependent on a parent namespace, so
    // parent should make sure all if its child namespace shutdown before it does.
    void FlushAndShutdown(fxl::RefPtr<Namespace> self,
                          fs::ManagedVfs::CloseAllConnectionsForVnodeCallback callback = nullptr);
  
    // Create child namespace. Returns |null| if the namespace is shutting down.
    static fxl::RefPtr<Namespace> CreateChildNamespace(
        fxl::RefPtr<Namespace>& parent, fxl::WeakPtr<Realm> realm,
        fuchsia::sys::ServiceListPtr additional_services,
        const std::vector<std::string>* service_allowlist);
  
   private:
    // So that constructor with parent namesapace cannot be used directly.
    struct PrivateConstructor {};
    enum Status {
      /// Namespace running and serving request.
      RUNNING,
  
      /// Got shutdown request.
      SHUTTING_DOWN,
  
      /// Stopping vfs and dependencies.
      STOPPING,
  
      /// Namespace stopped.
      STOPPED,
    };
  
    FRIEND_MAKE_REF_COUNTED(Namespace);
    Namespace(fxl::WeakPtr<Realm> realm, fuchsia::sys::ServiceListPtr additional_services,
              const std::vector<std::string>* service_allowlist);
  
    // Use CreateChildNamespace.
    Namespace(PrivateConstructor p, fxl::RefPtr<Namespace> parent, fxl::WeakPtr<Realm> realm,
              fuchsia::sys::ServiceListPtr additional_services,
              const std::vector<std::string>* service_allowlist);
  
    FRIEND_REF_COUNTED_THREAD_SAFE(Namespace);
    ~Namespace() override;
  
    void AddChild(fxl::RefPtr<Namespace> child);
  
    /// Removes child and returns true if the child was present.
    bool RemoveChild(Namespace* child);
  
    static void RunShutdownIfNoChildren(fxl::RefPtr<Namespace> ns);
  
    fidl::BindingSet<fuchsia::sys::Environment> environment_bindings_;
    fidl::BindingSet<fuchsia::sys::Launcher> launcher_bindings_;
    fidl::BindingSet<fuchsia::process::Resolver> resolver_bindings_;
  
    fs::ManagedVfs vfs_;
    fbl::RefPtr<ServiceProviderDirImpl> services_;
    fbl::RefPtr<JobProviderImpl> job_provider_;
    // realm_ can be null when it is shutting down and we kill namespace in background.
    fxl::WeakPtr<Realm> realm_;
    // Set if |additional_services.provider| was set.
    fuchsia::sys::ServiceProviderPtr service_provider_;
    // Set if |additional_services.host_directory| was set.
    zx::channel service_host_directory_;
    fuchsia::sys::LoaderPtr loader_;
  
    // Weak ptr to store in children namesapce.
    fxl::WeakPtrFactory<Namespace> weak_ptr_factory_;
  
    // List of children which have this namespace as its parent. Children should be shutdown before
    // this namespace is killed.
    std::map<Namespace*, fxl::RefPtr<Namespace>> children_;
  
    // Running status of this namespace.
    Status status_;
  
    // Callbacks to call when shutdown completes.
    std::vector<fs::ManagedVfs::CloseAllConnectionsForVnodeCallback> shutdown_callbacks_;
  
    // store parent reference
    fxl::WeakPtr<Namespace> parent_;
  
    FXL_DISALLOW_COPY_AND_ASSIGN(Namespace);
  };
  
  }  // namespace component
  
  #endif  // SRC_SYS_APPMGR_NAMESPACE_H_
  